防抖和節流

瀏覽器的 resizescrollkeypressmousemove 等事件在觸發時,會不斷地調用綁定在事件上的回調函數,極大地浪費資源,下降前端性能。爲了優化體驗,須要對這類事件進行調用次數的限制。前端

防抖(debounce)

做用是在短期內屢次觸發同一個函數,只執行最後一次,或者只在開始時執行。git

以用戶拖拽改變窗口大小,觸發 resize 事件爲例,在這過程當中窗口的大小一直在改變,因此若是咱們在 resize 事件中綁定函數,這個函數將會一直觸發,而這種狀況大多數狀況下是無心義的,還會形成資源的大量浪費。github

這時候可使用函數防抖來優化相關操做:數組

// 普通方案
window.addEventListener('resize', () => {
  console.log('trigger');
})複製代碼

優化方案:瀏覽器

// debounce 函數接受一個函數和延遲執行的時間做爲參數
function debounce(fn, delay){
    // 維護一個 timer
    let timer = null;
    
    return function() {
        // 獲取函數的做用域和變量
        let context = this;
        let args = arguments;
        
        clearTimeout(timer);
        timer = setTimeout(function(){
            fn.apply(context, args);
        }, delay)
    }
}複製代碼
function foo() {
  console.log('trigger');
}
// 在 debounce 中包裝咱們的函數,過 2 秒觸發一次
window.addEventListener('resize', debounce(foo, 2000));複製代碼
  • resize 事件上綁定處理函數,這時 debounce 函數會當即調用,實際上綁定的函數時 debounce 函數內部返回的函數。
  • 每一次事件被觸發,都會清除當前的 timer 而後從新設置超時調用。
  • 只有在最後一次觸發事件,才能在 delay 時間後執行。

咱們也能夠爲 debounce 函數加一個參數,能夠選擇是否當即執行函數markdown

function debounce(func, delay, immediate){
    var timer = null;
    return function(){
        var context = this;
        var args = arguments;
        if(timer) clearTimeout(timer);
        if(immediate){
            var doNow = !timer;
            timer = setTimeout(function(){
                timer = null;
            },delay);
            if(doNow){
                func.apply(context,args);
            }
        }else{
            timer = setTimeout(function(){
                func.apply(context,args);
            },delay);
        }
    }
}複製代碼

節流(throttle)

相似於防抖,節流是在一段時間內只容許函數執行一次。app

應用場景如:輸入框的聯想,能夠限定用戶在輸入時,只在每兩秒鐘響應一次聯想。前端性能

可經過時間戳和定時器來實現。函數

時間戳實現:oop

var throttle = function(func, delay){
    var prev = Date.now();
    return function(){
        var context = this;
        var args = arguments;
        var now = Date.now();
        if(now-prev>=delay){
            func.apply(context,args);
            prev = Date.now();
        }
    }
}複製代碼

定時器實現:

var throttle = function(func, delay){
    var timer = null;
    return function(){
        var context = this;
        var args = arguments;
        if(!timer){
            timer = setTimeout(function(){
                func.apply(context, args);
                timer = null;
            },delay);
        }
    }
}複製代碼

區別在於,使用時間戳實現的節流函數會在第一次觸發事件時當即執行,之後每過 delay 秒以後才執行一次,而且最後一次觸發事件不會被執行;而定時器實現的節流函數在第一次觸發時不會執行,而是在 delay 秒以後才執行,當最後一次中止觸發後,還會再執行一次函數。

相關文章

js:防抖動與節流

數組扁平化,柯里化,防抖,節流,對象拷貝

相關文章
相關標籤/搜索