[javascript] throttle 與 debounce,處理頻繁的 callback 執行頻率

在 javascript 的程式碼執行,採的是非同步的 callback 函式。

因此時常會是一個 event 觸發 callback 執行,但有時可能會頻繁的觸發事件(比如說瀏覽器的 resize 或 scroll 等等事件)

這時候如果每次觸發都執行 callback 可能不是這麼必要,甚至導致程式碼執行效率不佳

我們就可以透過 underscore.js throttle 或 debounce 的方法去優化這些 callback 的執行時間點。


  • debounce
    把短間隔時間(自行設定微秒)內重複觸發的事件合併為一個(自行設定觸發時間點),只呼叫一次 callback。
    像是當瀏覽器 resize 時,會頻繁觸發 resize 事件,使用 debounce 就可以達到視窗最後改變時再觸發 callback。
    下面例子,試著把滑鼠頻繁的在 Trigger area 中移動,可以看到 debounce 函數的實際效果。

    上面這個例子,可以看到當你在 Trigger area 頻繁移動滑鼠(400微秒內)時,僅會觸發一次的 callback

 

  • throttle
    限制 callback 執行的時間間隔必須大於所設定的時間,比如可以用再實作瀑布流排版時檢查 scroll 事件是否到達底部。(用 debounce 可能會變成滑到最底部才檢查)
    直接看下面這個範例比較容易懂~
    上面是一個監聽 scroll 事件的 callback, callback 時會把白色區塊的數字加一。(debounce 與 throotle 方法,時間都是設定 100 ms)
    試著滾動一下,可以發現 scroll 事件的 callback 觸發次數通常應該會是
    正常(每次都觸發 callback) > throttle(距離上次 callback 超過 100 ms 觸發 callback) > debounce(和上次的 scroll 間隔超過 100 ms 觸發 callback)。
     
    如果 callback 是會 render 畫面的話,我會比較建議使用 RequestAnimationFrame,詳細可參考這篇文章

 

程式碼的部分有點長,在這僅附上 underscore.js 的 opensource 連結,就不詳細解釋了:

debouncehttps://github.com/jashkenas/underscore/blob/master/underscore.js#L880,大體上就是每次觸發事件時會重置一個 callback 的 setTimeout 計時器(如:100 ms)。

throttlehttps://github.com/jashkenas/underscore/blob/master/underscore.js#L835,大體上就是利用 closure 把上次觸發 callback 的時間記下來,當呼叫 throttle 時超過設定的時間(如:100 ms)執行 callback。

 

參考資料:

http://www.cnblogs.com/jonkee/p/5124335.html

http://jinlong.github.io/2016/04/24/Debouncing-and-Throttling-Explained-Through-Examples/

https://css-tricks.com/the-difference-between-throttling-and-debouncing/

Leave a Reply