每日一題:什么是防抖和節(jié)流?有什么區(qū)別?如何實現(xiàn)

1. 什么是防抖節(jié)流

  • 防抖就是無論如何觸發(fā)事件,只在設定的n秒之后執(zhí)行時間,如果在n秒內再次觸發(fā)了事件,則重新計時
  • 節(jié)流就是在設定的時間內只觸發(fā)一次

2. 區(qū)別

  • 防抖以最后一次觸發(fā)為準,如果在設定的n秒內再次觸發(fā),則以新的事件時間為準
  • 節(jié)流以第一次觸發(fā)為準,執(zhí)行第一次時間后,在設定的n秒內觸發(fā)都不會執(zhí)行

3. 如何實現(xiàn)

  • 都利用了閉包
// 下面的代碼共用此綁定事件
function doSomething() {
    console.log('input')
}

var input = document.getElementById('input')
// 防抖
input.oninput = throttle(doSomething, 5000, {
    leading: false
})

// 節(jié)流
input.oninput = throttle(doSomething, 5000, {
    leading: false
})

防抖

  • 利用定時器
  • 思路:
    1. 如果在設定的時間內觸發(fā),清除定時器重新計時
    2. 重新設定定時器,利用apply/call執(zhí)行函數(shù)
    3. 可以增加立刻執(zhí)行選項
  function debounce(func, wait, immediate) {
      var timeout, result;
      return function () {
          var context = this; // 解決event指向問題
          var args = arguments; // 傳參
  
          if (timeout) clearTimeout(timeout);
          if (immediate) {
              // 如果已經執(zhí)行過,不再執(zhí)行
              var callNow = !timeout;
              timeout = setTimeout(function(){
                  timeout = null;
              }, wait)
              if (callNow) result = func.apply(context, args) // 只有立刻執(zhí)行有返回值,使用settimeout執(zhí)行函數(shù),因為異步原因,result為undefined
          } else { // 非立刻執(zhí)行保持原邏輯
              timeout = setTimeout(function(){
                  func.apply(context, args)
              }, wait);
          }
          return result;
      }
  }

節(jié)流

  • 利用定時器或時間戳
  • 總結:
    1. 時間戳方式:第一次進入立刻執(zhí)行;定時器:并不立刻執(zhí)行,在n秒之后執(zhí)行
    2. 時間戳:停止觸發(fā)了,就不執(zhí)行了,因為是根據(jù)觸發(fā)的時間去和上一次時間進行比較;定時器:停止觸發(fā)了,仍然會執(zhí)行
  • 思路:
    1. 結合兩種方式的優(yōu)點,既能立刻執(zhí)行,停止觸發(fā)也能執(zhí)行最后一次
    2. 分兩種判斷邏輯:1. 時間戳 2. 定時器;定時器為空(第一次進入或定時器執(zhí)行完成后)時進入時間戳邏輯;其余是進入定時器邏輯
function throttle(fn, wait, options) {
       var timeout = null, pre = 0;
        var context,arg;
        if (!options) options = {};


       var throttled = function () {
           context = this;
           arg = arguments;
           var now = +new Date();
           if (!pre && options.leading === false) pre = now; // +++ 禁止立刻執(zhí)行,remaining > 0, 執(zhí)行定時器邏輯
           var remaining = wait - (now - pre); // 計算還剩下多少時間執(zhí)行下一次方法
           // 時間戳:立刻執(zhí)行,第一次進入remaining必小于0,因為wait-now
           if (remaining <= 0) {
               console.log('時間戳')
               if (timeout) {
                   clearTimeout(timeout) // 第一次進入,清除定時器,為后面做準備
                   timeout = null
               }
               pre = now; // now時間賦值pre,頻繁觸發(fā)時,基本不會出現(xiàn)remaining <= 0,會走下面的邏輯
               fn.apply(context, arg)
               if (!timeout) context = arg = null; // +++ 不太明白,或許是手動清除內存?
           } else if (!timeout && options.trailing !== false) { // +++ 增加options.trailing !== false判斷,停止觸發(fā)不設置定時器了
               console.log('定時器')
               timeout = setTimeout(function () {
                   pre = options.leading === false ? 0 : +new Date(); // +++ 如果需要禁止立刻執(zhí)行,需要重新將pre重置為0,避免進入時間戳邏輯
                   timeout = null;
                   fn.apply(context, arg)
                   if (!timeout) context = arg = null; // +++ 不太明白,或許是手動清除內存?
               }, remaining)
           }
       }

        throttled.cancel = function () {
            clearTimeout(timeout)
            pre = 0;
            timeout = null
        }
       return throttled;
}

參考鏈接

  1. 防抖
  2. 節(jié)流
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容