防抖節流詳解


防抖(debounce)和節流(throttle)是什么,如何實現它們,它們之間又有什么區別呢?

在前端開發中會遇到一些頻繁的事件觸發,比如:

  • windowresizescroll
  • mousedownmousemove
  • keyupkeydown

如何解決:防抖、節流

防抖

動作綁定事件,動作發生后一定時間后觸發事件,在這段時間內,如果該動作又發生,則重新等待一定時間再觸發事件。

具體方法是:在上一次事件觸發之后的 time 時間內如果事件沒有再次觸發,那么就在 time 時間后觸發,否則將觸發的時間作為新的起始點

通俗理解就是,將密集的時間觸發事件看作一個時間整體,整個整體只觸發一次事件,密集的界定就是相鄰事件觸發時間小於 time,則以這個整體的最后一次事件觸發為起始點

可以用數軸來理解,比如有 [2, 5][8, 11] 兩個區間可以看作密集事件發生處,那么整個 [2, 5] 時間最終都只觸發一次事件,5 是這次事件結束時,那么等待 time = 3 才再次觸發下一次事件

具體代碼:

function debounce(func, time) {
  let timer = null;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, arguments);
    }, time);
  };
}

這里有一個疑惑,為什么要使用閉包?

原因是 timer 變量是在 debounce 函數內部初始化的時候聲明的,但是之后每一次觸發返回的箭頭函數的時候都需要讀取 timer 變量,所以要使用閉包

還有一個疑惑,為什么要使用 func.apply(this, arguments) 而不直接使用 func()

原因是每次調用箭頭函數的時候為了確保上下文環境為當前的 this,就需要使用 apply 語法

節流

動作綁定事件,動作發生后一段時間后觸發事件,在這段時間內,如果動作又發生,則無視該動作,直到事件執行完后,才能重新觸發。

節流和防抖大致相同,不同點在於:

  • 防抖是“隨機應變”,以密集的事件觸發處的末尾為下一次事件觸發的計時開始處
  • 節流是“鐵打不動”,始終以第一次事件觸發為起始點,忽略 time 時間內的所有事件,第一次事件發生 time 事件之后觸發第二次事件

在數軸上理解的相同點和區別為:

[2, 5] 時間內觸發的所有事件都濃縮為一次事件,區別是:防抖將此次事件的發生事件定在最后一次事件觸發的時間,節流將時間定在第一次事件觸發的時間

節流的代碼:

function throtte(func, time) {
  let activeTime = 0;
  return function () {
    const current = Date.now();
    if (current - activeTime > time) {
      func.apply(this, arguments);
      activeTime = Date.now();
    }
  };
}

從代碼的區別也可以看出:

防抖實際上是在事件密集觸發區不斷更新定時器,而節流只需要不斷讀取當前時間並且判斷是否滿足要求即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM