JavaScript 中的函數節流與防抖

一、是什麼

本質上是優化高頻率執行代碼的一種手段

如:瀏覽器的 resizescrollkeypressmousemove 等事件在觸發時,會不斷地調用綁定在事件上的回調函數,極大地浪費資源,降低前端性能

爲了優化體驗,需要對這類事件進行調用次數的限制,對此我們就可以採用throttle(節流)和debounce(防抖)的方式來減少調用頻率

定義

一個經典的比喻:

想象每天上班大廈底下的電梯。把電梯完成一次運送,類比爲一次函數的執行和響應

假設電梯有兩種運行策略 debouncethrottle,超時設定爲 15 秒,不考慮容量限制

電梯第一個人進來後,15 秒後準時運送一次,這是節流

電梯第一個人進來後,等待 15 秒。如果過程中又有人進來,15 秒等待重新計時,直到 15 秒後開始運送,這是防抖

代碼實現

節流

完成節流可以使用時間戳與定時器的寫法

使用時間戳寫法,事件會立即執行,停止觸發後沒有辦法再次執行

使用定時器寫法,delay毫秒後第一次執行,第二次事件停止觸發後依然會再一次執行

可以將時間戳寫法的特性與定時器寫法的特性相結合,實現一個更加精確的節流。實現如下

function throttled(fn, delay) {
    let timer = null
    let starttime = Date.now()
    return function () {
        let curTime = Date.now() // 當前時間
        let remaining = delay - (curTime - starttime)  // 從上一次到現在,還剩下多少多餘時間
        let context = this
        let args = arguments
        clearTimeout(timer)
        if (remaining <= 0) {
            fn.apply(context, args)
            starttime = Date.now()
        } else {
            timer = setTimeout(fn, remaining);
        }
    }
}

防抖

簡單版本的實現

function debounce(func, wait) {
    let timeout;

    return function () {
        let context = this; // 保存this指向
        let args = arguments; // 拿到event對象

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

防抖如果需要立即執行,可加入第三個參數用於判斷,實現如下:

function debounce(func, wait, immediate) {

    let timeout;

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

        if (timeout) clearTimeout(timeout); // timeout 不爲null
        if (immediate) {
            let callNow = !timeout; // 第一次會立即執行,以後只有事件執行後纔會再次觸發
            timeout = setTimeout(function () {
                timeout = null;
            }wait)
            if (callNow) {
                func.apply(context, args)
            }
        }
        else {
            timeout = setTimeout(function () {
                func.apply(context, args)
            }wait);
        }
    }
}

二、區別

相同點:

不同點:

例如,都設置時間頻率爲 500ms,在 2 秒時間內,頻繁觸發函數,節流,每隔 500ms 就執行一次。防抖,則不管調動多少次方法,在 2s 後,只會執行一次

如下圖所示:

三、應用場景

防抖在連續的事件,只需觸發一次回調的場景有:

節流在間隔一段時間執行一次回調的場景有:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/s5buGAZVTAqjD9pQC_UgPw