一次性弄懂debounce

程式設計師大白發表於2018-08-20

debounce是啥?

debounce一般被稱為防抖動函式,核心目的在於減少函式被觸發的頻率,從而提高效能。

使用場景

  • 減少resize、mousemove、 scroll等會頻繁觸發的事件執行次數。比如說我可以通過debounce做到resize結束後100ms才觸發事件(因為我們可能不想resize事件被頻繁觸發,只需要視窗調整結束後再觸發即可)
  • 減少ajax請求次數。比如說現在有個需求,要求實現一個使用者輸入資訊的同時從資料庫查詢相關資訊並在前臺進行展示,那麼很顯然,如果直接繫結input事件的話在使用者輸入的過程中此事件會頻繁觸發從而導致在短時間內傳送多次ajax,一方面會影響效能,另一方面可能會導致使用者都輸入4個查詢關鍵字了第一次的查詢才剛返回,這就會導致查詢結果和使用者輸入不一致的情況,使用者體驗不好。這種情況其實也可以用debounce來加以解決,如果使用者一直在輸入就不觸發ajax請求,等使用者停止輸入100ms後立即傳送ajax請求。

總之,debounce可以用來控制某個函式被觸發的頻率,從而提高效能和使用者體驗

不同的debounce實現

若干時間後觸發(事件連續發生時不觸發,等到事件發生結束後若干時間才觸發操作,比如說等使用者調整視窗大小結束後200ms再列印日誌)

function debounce(func, wait) {
    var timeout=null;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function () {
            func.apply(context, args);
            clearTimeout(timeout);
            timeout=null;
        }, wait || 500);
    }
}

// 使用者每次停止調整視窗大小200ms後列印日誌
window.onresize=debounce(function(){
    console.log('hello world');
},200);
複製程式碼

立即觸發(事件首次發生時觸發,後續連續發生的話不觸發事件)

function immediate(func, wait) {
    var flag = true;
    var timeout = null;

    return function () {
        if (flag) {
            flag = false;
            return func.apply(this, arguments);
        }

        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function () {
            flag = true;
        }, wait);
    }
};

// 使用者開始調整視窗大小時記錄日誌,後續連續觸發的話不記錄日誌,隔一段時間後首次觸發再次記錄日誌
window.onresize = immediate(function () {
    console.log('hello world');
}, 200);
複製程式碼

將延期執行和立即執行合併下(其實就是給debounce函式加個isImmediate引數,有引數的話就在動作發生後立即執行,否則就在動作連續執行後若干時間再執行)

function debounce(func, wait, isImmediate) {
    if (isImmediate) {
        return immediate(func, wait);
    } else {
        return delayDebounce(func,wait);
    }
}

function immediate(func, wait) {
    var flag = true;
    var timeout = null;

    return function () {
        if (flag) {
            flag = false;
            return func.apply(this, arguments);
        }

        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function () {
            flag = true;
        }, wait);
    }
};

function delayDebounce(func, wait) {
    var timeout = null;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function () {
            func.apply(context, args);
            clearTimeout(timeout);
            timeout = null;
        }, wait || 500);
    }
}

// 使用者調整視窗後立即執行
window.onresize = debounce(function () {
    console.log('hello world');
}, 200, true);

// 使用者調整視窗結束若干時間後執行
window.onresize = debounce(function () {
    console.log('hello world');
}, 200);
複製程式碼

結語

效能優化應該是每個熱愛技術的寶寶繞不過的坎,所以,既然繞不過,那就在效能調優的深海里浪裡個浪好啦,O(∩_∩)O哈哈~

相關文章