函數防抖與函數節流

概念

函數防抖(debounce)

當調用動作過n毫秒后,才會執行該動作,若在這n毫秒內又調用此動作則將重新計算執行時間

函數節流(throttle)

預先設定一個執行周期,當調用動作的時刻大于等于執行周期則執行該動作,然后進入下一個新周期

函數節流(throttle)

函數防抖(debounce)都是為了限制函數的執行頻次,以優化函數觸發頻率過高導致的響應速度跟不上觸發頻率,出現延遲,假死或卡頓的現象。

比如如下的情況:

  • window對象的resize、scroll事件
  • 拖拽時的mousemove事件
  • 文字輸入、自動完成的keyup事件

可以拿我們平時坐電梯為例來形象地表述二者的區別

函數防抖:如果有人進電梯(觸發事件),那電梯將在10秒鐘后出發(執行事件監聽器),這時如果又有人進電梯了(在10秒內再次觸發該事件),我們又得等10秒再出發(重新計時)。

函數節流

:保證如果電梯第一個人進來后,10秒后準時運送一次,這個時間從第一個人上電梯開始計時,不等待,如果沒有人,則不運行

實現

函數防抖(debounce)

function _debounce(fn,wait){
    var timer = null;
    return function(){
        clearTimeout(timer)
        timer = setTimeout(()=>{
            fn()
        },wait)
    }
}

function _log(){
    console.log(1)
}
window.onscroll = _debounce(_log,500)

但是,仔細想想,上面的實現方式還是有一定的缺點。如果頁面很長,我們一直在滾動頁面,那_log方法就一直不會被執行。所以我們可以升級一下上述的防抖方法。

function _debounce(fn,wait,time){
    var previous = null; //記錄上一次運行的時間
    var timer = null;

    return function(){
        var now = +new Date();

        if(!previous) previous = now;
        //當上一次執行的時間與當前的時間差大于設置的執行間隔時長的話,就主動執行一次
        if(now - previous > time){
            clearTimeout(timer);
            fn();
            previous = now;// 執行函數后,馬上記錄當前時間
        }else{
            clearTimeout(timer);
            timer = setTimeout(function(){
                fn();
            },wait);
        }
    }
}
function _log(){
    console.log(1)
}
window.onscroll = _debounce(_log,500,2000)

函數節流(throttle)

function _throttle(fn, time) { 

  let _self = fn, 
      timer,  
      firstTime = true //記錄是否是第一次執行的flag

  return function() { 
    let args = arguments, //解決閉包傳參問題
        _me = this //解決上下文丟失問題

    if(firstTime) { //若是第一次,則直接執行
      _self.apply(_me, args)
      return firstTime = false
    }
    if(timer) { //定時器存在,說明有事件監聽器在執行,直接返回
      return false
    }

    timer = setTimeout(function() { 
      clearTimeout(timer)
      timer = null
      _self.apply(_me, args)
    }, time || 500)
  }
}

function _log(){
    console.log(1)
}
window.onscroll = _throttle(_log,500)

ES6中的函數防抖和函數節流

//函數節流
const throttle = (fun,  delay) => {
    let last = null;
    return () => {
        const now = + new Date();
        if (now - last > delay) {
            fun();
            last = now;
        }
    }
}
//實例
const throttleExample  = throttle(() => console.log(1), 1000);
//調用
throttleExample();
throttleExample();
throttleExample();
//函數防抖
const debouce = (fun, delay) => {
    let timer = null;
    return () => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fun();
        }, delay);
    }
}
//實例
const debouceExample = debouce(() => console.log(1), 1000);
//調用
debouceExample();
debouceExample();
debouceExample();
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • debounce -- 函數防抖,throttle -- 函數節流都是在JavaScript中可以限制函數發生頻率...
    Quilljou閱讀 446評論 0 3
  • 前言 在類似scroll、resize事件中執行大量DOM操作或者計算時,就會出現再次觸發事件而上一次事件中的DO...
    王阿王閱讀 1,006評論 0 2
  • 函數節流 還記得上篇文章中說到的圖片懶加載嗎?我們在文章的最后實現了一個頁面滾動時按需加載圖片的方式,即在觸發滾動...
    柏丘君閱讀 2,875評論 1 19
  • 函數節流(throttle)與 函數防抖(debounce)都是為了限制函數的執行頻次,以優化函數觸發頻率過高導致...
    _Dot912閱讀 819評論 0 6
  • 我們相識的曾經, 筆尖寫不下溫存。 我帶著你最初的純, 默默數著歲月的年輪。 我已走過了曾經的曾經, 時光刻下了深...
    南宮詩萌閱讀 214評論 2 3