前端都應該要掌握的防抖和節流

初見雨夜發表於2022-04-20

說到防抖和節流相信大家都不陌生,這兩個東西大家可能多多少少都有用到過,最少也有聽過

古人云,溫故而知新。雖然可能已經很熟悉防抖和節流了,但不妨再看一看鞏固一下知識

什麼?你說你不僅不會手寫防抖和節流,也沒有聽過。那也沒事,下文會詳細介紹的

防抖和節流有什麼用?

簡單來說,防抖和節流都是用來減少函式執行的頻率,以達到優化專案效能或者實現特定功能的效果

防抖

定義:事件被觸發一定時間後再執行回撥。如果在這段時間內又被觸發了,則重新開始計算時間

常用場景

  • 輸入框遠端查詢事件
  • 線上文件自動儲存
  • 瀏覽器視口大小改變

例子

張三在某平臺搜尋一本書籍,發現搜尋建議並不是瞬間就出現的,而是自己輸入片語結束後出現的。那麼該平臺在此搜尋框可能做了什麼操作?

程式碼實現

<body>
  <input type="text" id="searchElement" />
</body>
<script>
  const searchElement = document.getElementById('searchElement');
  const debounce = (fn, initial) => {
    let timer = null;
    return () => {
      clearTimeout(timer);
      timer = setTimeout(fn, initial);
    };
  };

  searchElement.oninput = debounce(function (event) {
    const value = searchElement.value;
    if (value) console.log(value, '請求值');
  }, 1000);
</script>

節流

定義:在單位時間內只觸發一次函式,若單位時間內多次觸發只有一次生效

常用場景

  • 按鈕提交事件(當然也可做成點選後就loading)
  • 頁面滾動事件的觸發
  • 累計計算滑鼠移動距離

例子

張三參加某平臺週年慶活動,他選購了某熱門飲品並一直點選搶購按鈕,卻發現並不是每次點選都會有響應的。那麼該平臺前端可能做了什麼限制?

程式碼實現

<body>
  <button type="submit" id="buttonElement">搶購</button>
</body>
<script>
  function throttle(fn, interval) {
    let timer;
    return (event) => {
      if (timer) return false;
      timer = setTimeout(() => {
        clearTimeout(timer);
        timer = null;
        fn(event);
      }, interval);
    };
  }

  var btnClick = document.getElementById('buttonElement');
  btnClick.addEventListener('click', throttle(function (event) {
    console.log(event, '點選了')
  }, 1000));
</script>

可以看到,張三瘋狂點選搶購,但還是每秒只響應1次

節流(立即執行)

細心的同學可能發現了,上面這個程式碼有個弊端,那就是在張三第一次點選的時候也隔了1秒才響應,這不免也太坑了。正常來說第一次應該直接響應的,並且在連續點選結束後的第一次也應該立即觸發,其實想實現這樣的效果也不難

<body>
  <button type="submit" id="buttonElement">搶購</button>
</body>
<script>
  function throttle2(fn, interval) {
      let init = false; // 引入一個引數記錄狀態
      let timer;
      return (event) => {
          if (init) return;
          init = true;
          clearTimeout(timer);
          timer = setTimeout(() => {
              init = false;
          }, interval);
          fn(event);
      }
  }

  var btnClick = document.getElementById('buttonElement');
  btnClick.addEventListener('click', throttle2(function (event) {
      console.log(event, '點選了')
  }, 2000));
</script>

可以看到第一次點選直接列印,第二次瘋狂點選只列印一次,最後一次點選也是直接列印

引入Lodash實現

GitHub地址:https://github.com/lodash/lodash
官方文件:https://www.lodashjs.com/

防抖

import _ from 'lodash';
debounceHandle: _.debounce(function() {
  console.log('業務程式碼');
}, 2000, {       // 在n毫秒內觸發
  leading: true, // 第一次點選立刻執行,預設為true
  trailing: true // 節流結束後立刻執行,預設為true
});

節流

import _ from 'lodash';
throttleHandle: _.throttle(function() {
  console.log("業務程式碼");
}, 2000);

相關文章