一般綁定 DOM 事件(resizescrollmousemovekeydown/keyup/keypress等)的時候,常常會因為事件觸發的太頻繁而導致網頁效能低落。

所以我們可以在事件要執行前加一個控制器,降低事件的觸發頻率,最常使用的就是debouncethrottle 這兩個方法,兩者都是用來控制某個事件在一定時間內執行多少次數,看起來非常相似但又有些不同。

Debounce

用戶停止某個操作一段時間之後才執行相應的監聽事件
例如,調整瀏覽器視窗大小的時候,會觸發很多次 resize 事件,可以使用 debounce 方法在停止調整視窗大小的時候在去觸發相應功能。

Debounce

造輪子

觸發 -> 記錄觸發時間 -> 上次動作觸發時間大於限制時間 -> 執行動作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 強制一個事件在某個連續時間段內只執行一次.
*
* @param {function} func 實際要執行的事件
* @param {number} delay 延遲時間,單位是毫秒(ms)
* @param {boolean} immediate 設置為ture時,觸發於開始而不是結束
* @return {function} 返回客戶呼叫事件
*/
function debounce(func, delay, immediate) {
var timer;
return function() {
var context = this,
args = arguments;
var later = function() {
timer = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(later, delay);
if (callNow) func.apply(context, args);
};
};

參數 immediate,設定函數在一個時間區間的最開始(true)執行,還是最後(false)執行。

呼叫方式

1
2
3
4
5
var handleScroll = debounce(function() {
// Do fun stuff​.
}, 250);

window.addEventListener('scroll', handleScroll);

Throttle

控制監聽事件固定在每 X 毫秒內執行一次
例如,不管滑鼠移動(mousemove事件)的速度多快,固定在每 250ms 執行一次。

Throttle

造輪子

觸發 -> 上次動作執行時間大於限制時間 -> 執行動作,記錄執行時間
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 固定事件執行的速率.
*
* @param {function} func 實際要執行的事件
* @param {number} delay 執行間隔,單位是毫秒(ms)
* @return {function} 返回一個「節流」事件
*/
function throttle(func, delay) {
var last, timer;
delay || (delay = 250);
return function() {
var context = this;
var args = arguments;
var now = +new Date();
if (last && now < last + delay) {
clearTimeout(timer);
timer = setTimeout(function() {
last = now;
func.apply(context, args);
}, delay);
} else {
last = now;
func.apply(context, args);
}
}
}

呼叫方式

1
2
3
4
5
var handleScroll = throttle(function() {
// Do fun stuff​.
}, 250);

window.addEventListener('scroll', handleScroll);

使用 Underscore.js 中的 _.debounce_.throttle

不想重新造輪子的話可以直接使用 UnderscoreLodash

另外可以使用 Lodash 的指令列工具,產生只有 _.debounce_.throttle 的壓縮檔。

1
2
npm i -g lodash-cli
lodash include = debounce, throttle

呼叫方式

1
2
3
$(window).on('scroll', _.debounce(doSomething, 250));

$(window).on('scroll', _.throttle(doSomething, 250));

參考資料