【轉】函數防抖與函數節流

原文地址:https://zhuanlan.zhihu.com/p/38313717

函數防抖與節流是很相似的概念,但它們的應用場景不太一樣。

我們先從概念上深刻理解它們。

先說函數防抖,debounce。其概念其實是從機械開關和繼電器的“去彈跳”(debounce)衍生出來的,基本思路就是把多個信號合併爲一個信號。

單反也有相似的概念,在拍照的時候手如果拿不穩晃的時候拍照一般手機是拍不出好照片的,因此智能手機是在你按一下時連續拍許多張, 能過合成手段,生成一張。翻譯成JS就是,事件內的N個動作會變忽略,只有事件後`由程序觸發`的動作只是有效。

實現思路如下,將目標方法(動作)包裝在setTimeout裏面,然後這個方法是一個事件的回調函數,如果這個回調一直執行,那麼這些動作就一直不執行。爲什麼不執行呢,我們搞了一個clearTimeout,這樣setTimeout裏的方法就不會執行! 爲什麼要clearTimeout呢,我們就需要將事件內的連續動作刪掉嘛!待到用戶不觸發這事件了。那麼setTimeout就自然會執行這個方法。

那麼這個方法用在什麼地方呢,就是用於input輸入框架的格式驗證,假如只是驗證都是字母也罷了,太簡單了,不怎麼耗性能,如果是驗證是否身份證,這性能消耗大,你可以隔170ms才驗證一次。這時就需要這個東西。或者你這個是自動完全,需要將已有的輸入數據往後端拉一個列表,頻繁的交互,後端肯定耗不起,這時也需要這個,如隔350ms。

function debounce(func, delay) {
    var timeout;
    return function(e) {
        console.log("清除",timeout,e.target.value)
        clearTimeout(timeout);
        var context = this, args = arguments
        console.log("新的",timeout, e.target.value)
        timeout = setTimeout(function(){
          console.log("----")
          func.apply(context, args);
        },delay)
    };
};

var validate = debounce(function(e) {
    console.log("change", e.target.value, new Date-0)
}, 380);

// 綁定監聽
document.querySelector("input").addEventListener('input', validate);

 

 

這個保證了正常的用戶每輸入1,2個字符就能觸發一次。如果用戶是輸入法狂魔,也可以狠制他每輸入3~6個字符觸發一次。

這個方法的重點是,它在用戶不觸發事件的時,才觸發動作,並且抑制了本來在事件中要執行的動作。

其他應用場合:提交按鈕的點擊事件。

 

再看節流,throttle。節流的概念可以想象一下水壩,你建了水壩在河道中,不能讓水流動不了,你只能讓水流慢些。換言之,你不能讓用戶的方法都不執行。如果這樣幹,就是debounce了。爲了讓用戶的方法在某個時間段內只執行一次,我們需要保存上次執行的時間點與定時器。

 

 <div id='panel' style="background:red;width:200px;height:200px">

 </div>
function throttle(fn, threshhold) {
 var timeout
 var start = new Date;
 var threshhold = threshhold || 160
 return function () {

 var context = this, args = arguments, curr = new Date() - 0
 
 clearTimeout(timeout)//總是幹掉事件回調
 if(curr - start >= threshhold){ 
     console.log("now", curr, curr - start)//注意這裏相減的結果,都差不多是160左右
     fn.apply(context, args) //只執行一部分方法,這些方法是在某個時間段內執行一次
     start = curr
 }else{
 //讓方法在脫離事件後也能執行一次
     timeout = setTimeout(function(){
        fn.apply(context, args) 
     }, threshhold);
    }
  }
}
var mousemove = throttle(function(e) {
 console.log(e.pageX, e.pageY)
});

// 綁定監聽
document.querySelector("#panel").addEventListener('mousemove', mousemove);

函數節流會用在比input, keyup更頻繁觸發的事件中,如resize, touchmove, mousemove, scroll。throttle 會強制函數以固定的速率執行。因此這個方法比較適合應用於動畫相關的場景。

 

如果還是不能完全體會 debounce 和 throttle 的差異,可以到 這個頁面 看一下兩者可視化的比較。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章