在 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 連結,就不詳細解釋了:
debounce
:https://github.com/jashkenas/underscore/blob/master/underscore.js#L880,大體上就是每次觸發事件時會重置一個 callback 的 setTimeout 計時器(如:100 ms)。
throttle
:https://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/