Skip to main content

Command Palette

Search for a command to run...

Debounce 防彈跳 & Throttle 節流

Published

簡介

Debounce 和 Throttle 常用在 inputscrollresize 等事件進行控制,防止事件過多觸發,減少資源消耗或是商業邏輯上的維護成本。這兩者最大的差異在於觸發的時機。

  • debounce(func, wait, options):建立並回傳函數的防彈跳版本,將延遲函數的執行(真正的執行)在函數最後一次調用時刻的 wait 毫秒之後,對於必須在一些輸入(多是一些用戶操作)停止之後再執行的行為有幫助。將一個連續的調用歸類為一個,如果連續在 wait 毫秒內調用,只有最後一次會執行
  • throttle(func, wait, options):建立並返回一個像節流閥一樣的函數,當重復調用函數的時候,最多每隔指定的 wait 毫秒調用一次該函數;不允許方法在每 wait 毫秒間執行超過一次,如果連續在 wait 毫秒內調用,最後執行會均勻分布在大約每 wait 一次

使用場景

  • 滑鼠移動時減少計算次數:debounce
  • 在輸入框中輸入文字時自動發送 Ajax 請求進行自動補全: debounce
  • API 請求合併,不希望短時間內大量的請求被重復發送:debounce
  • 縮放畫面重新計算樣式或佈局:debouncethrottle
  • 滾動時觸發操作:throttle
  • 對使用者輸入的驗證,不想停止輸入再進行驗證,而是每 n 秒進行驗證:throttle

Debounce 防彈跳

在事件被觸發 n 秒後,再去執行 callback。如果 n 秒內被重新觸發,則重新計時。

基本函數架構

function debounce(delay, callback) {
    let timeoutID;

    function wrapper() {
        const self = this;
        const args = arguments;

        function exec() {
            callback.apply(self, args);
        }
        // 重新計時
        clearTimeout(timeoutID);
        timeoutID = setTimeout(exec, delay);
    }

    return wrapper;
}

使用範例

let reduceEvent
function debounce(cb, delay) {
    if (!reduceEvent) {
        reduceEvent = setTimeout(() => {
            cb();
            console.log('執行啦!!');
            reduceEvent = null;
        }, delay);
    }
}

setTimeout(() => debounce(() => console.log(1), 2000), 1000) // Output: 1 執行啦!!
setTimeout(() => debounce(() => console.log(2), 2000), 2000)
setTimeout(() => debounce(() => console.log(3), 2000), 2000)
setTimeout(() => debounce(() => console.log(4), 2000), 4000) // Output: 4 執行啦!!

Throttle 節流

在規定時間內,將觸發的事件合併成一次執行。降低高頻率事件觸發的頻次

function throttle(method, wait) {
    // 對比時間,初始化為 0 則首次觸發立即執行,初始化為當前時間,則 wait 毫秒後觸發才會執行
    let previous = 0;
    return function(...args) {
        let context = this;
        let now = new Date().getTime();

        // 間隔大於 wait 則執行 method 並更新對比時間戳
        if (now - previous > wait) {
            method.apply(context, args);
            previous = now;
        }
    }
}
function throttle(method, wait) {
    let timeout;

    return function(...args) {
        let context = this;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                method.apply(context, args);
            }, wait);
        }
  }
}

使用範例

function throttle(func, wait = 200) {
    let last = 1
    let timer
    return function(...rest) {
        const now = +new Date()
        if (last && now - last < wait) {
            clearTimeout(timer)
            timer = setTimeout(() => {
                last = now
                func.apply(this, rest)
            }, wait)
        } else {
            last = now
            func.apply(this, rest)
            clearTimeout(timer)
        }
    }
}
const task = throttle(() => console.log(1), 2000)
setTimeout(task, 0)
setTimeout(task, 500)
setTimeout(task, 1000)
setTimeout(task, 2000) // Output: 1 1

Reference

More from this blog

如何開始入門軟體工程領域 - 名詞解釋(長期更新)

現在應該開始有很多人想要踏入軟體工程的領域,但在進入這個領域之前,覺得先了解一些名詞,可以在入門時更有方向也更知道要用什麼關鍵字去找尋有用的資訊。這篇文章就是想要幫助想要入門的人理解一些軟體工程裡的專有名詞。 作業系統 這一區塊主要解釋跟作業系統層面相關的名詞 英文中文解釋 Operation system 簡稱 OS | 作業系統 | 就是電腦的作業系統,是三大作業系統分別是:Linux、Windows、macOS | | Linux | | 自由和開放原始碼的 UNI...

May 10, 2023

我的 MacBook Pro (Apple Silicon) 設定

現在開始因為 ChatGPT 的出現,各種 AI 助手的功能都跑出來了。想想自己用了許久的環境設定也應該要來重新審視和建立新的開發環境了,僅此紀錄我個人的環境配置步驟和設定。 環境前置步驟 還原 MacBook Pro 至全新環境 macOS(全部資料刪除) 設定好初始設定後,登入 Apple ID 進入 App Store 確定 macOS 版本和預設 APP 都更新到最新 macOS 版本 到系統設定調整所有設定至個人習慣的設定 三指拖移 觸控板手勢開啟 防火牆開啟 輸入法設定...

Apr 25, 2023

ChatGPT 下的發展預想

從 ChatGPT 問世到現在,有許許多多的文章和討論出來。先從最早的 Google 要完蛋了,到後來的工作要被取代了,工程師失業了。 我就比較沒有想要馬上出來評論一下,我喜歡讓子彈飛一會兒。跟討論一下我自己比較在意的討論點。 Google 為什麼慢了? 結論:因為他需要更小心 很多人說 Google 怎麼被微軟搶先了一步。剛開始 Bing 說要加上 AI 的時候大家都在說 Google 怎麼慢了。我就馬上跑去看 OpenAI 的網站,靠北呀啊就 Azure 贊助的。那當然在正式上線 ChatG...

Mar 23, 2023

不工程的攻城獅

223 posts

I am not a programmer because I am not good at programming. But I do programming. Love to learn new things. An animal lover and a dancer. My oshi is 潤羽るしあ.