函數防抖Debounce和函數節流Throttle

函數節流 & 函數防抖

函數節流和函數防抖前端

函數節流和函數防抖兩者很容易被混淆起來。下面貼英文原文,建議認真閱讀:
Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called".
Throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds".ajax

函數節流:確保函數特定的時間內至多執行一次。
函數防抖:函數在特定的時間內不被再調用後執行。瀏覽器

上面的概念可能仍是不夠清晰,下面均以「輸入框輸入文字觸發ajax獲取數據」爲例,分別以防抖和節流的思想來優化,兩者的區別:性能優化

輸入框輸入文字以下:1111111111111111111111(停頓3s繼續輸入)11111111111111111
函數防抖:當用戶持續輸入1的過程當中,並不會發送ajax,當用戶中止輸入2s後,發送ajax請求,以後到第3s後,用戶繼續輸入1的過程當中,依舊不會發送ajax,當用戶中止輸入2s後,又觸發ajax請求。
函數節流:當用戶持續輸入1的過程當中(假設輸入1的過程超過2s了),從你開始輸入1開始計時,到第2s,發送ajax請求。函數節流與你是否中止輸入無關,是一種週期性執行的策略。
一句話歸納:函數節流是從用戶開始輸入就開始計時,而函數節流是從用戶中止輸入開始計時。app

場景分析前端性能

函數節流(throttle)函數

  1. 頻繁的mousemove/keydown,好比高頻的鼠標移動,遊戲射擊類的
  2. 搜索聯想(keyup)
  3. 進度條(咱們可能不須要高頻的更新進度)
  4. 拖拽的dragover等
  5. 高頻的點擊,抽獎等
  6. 無限滾動(用戶向下滾動無限滾動頁面,要檢查滾動位置距底部多遠。若是離底部進了,發ajax請求獲取更多數據插入頁中)

函數防抖(debounce)性能

  1. scroll/resize事件,瀏覽器改變大小,有人說是throttle
  2. 文本連續輸入,ajax驗證/關鍵字搜索

注:throttle和debounce均是經過減小實際邏輯處理過程的執行來提升事件處理函數運行性能的手段,並無實質上減小事件的觸發次數。優化

使用函數節流是進行前端性能優化的方法之一,例如,懶加載的實現。this

實現函數防抖和函數節流

函數防抖

function debounce(func,wait){
    var timeout;
    return function(){
        var context=this;//用來保存this的正確指向
        var args=arguments;//用來保存觸發的事件類型,例如keyboard event
        clearTimeout(timeout);//每次都從新開始計時
        timeout=setTimeout(function(){
            func.apply(context,args);
        },wait);
    }
}
a.onkeyup=debounce(getValue,3000);
function getValue(){
    console.log(this.value);//使用debounce調用它時,this就變爲window
}

函數節流

function throttle(func, wait) {
    var timeout, context, args, result;
    var previous = 0;
 
    var later = function() {
        previous = +new Date();
        timeout = null;
        func.apply(context, args)
    };

    var throttled = function() {
        var now = +new Date();
        //下次觸發 func 剩餘的時間
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
         // 若是沒有剩餘的時間了或者你改了系統時間
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
        } else if (!timeout) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}
相關文章
相關標籤/搜索