throttle 和 debounce 是两个控制方法调用频率的高阶函数。

本文比较了这两个函数的区别和使用场景。

throttle:

使得某个函数在每间隔一段时间内执行不大于一次。

用通俗的例子来描述:某个函数去乘地铁。地铁每隔一段固定时间发车。不管乘客怎么源源不断地来,都得等一段时间,在地铁进站后才能上车;

下图示中 X是一个被 throttled 的函数实际执行的时机

||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
X X X X X X X X X X X X

throttle的使用场景:

  • resize 事件
  • mouse move 事件
  • scroll 事件

当基于性能、效率上的考虑,要限制函数的执行频率时可以使用 throttle

实现

throttle = function(fn, threshold=250) {
var last
var timer

return function () {
var context = this
var args = arguments
var now = +new Date()

if (last && now < last + threshold) {
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, threshold)
} else {
// 第一次执行、或者超过时间阈值
last = now
fn.apply(context, args)
}
}
}

debounce:

使得某个函数在一段时间阈值内执行且只执行一次。

这个也可以举个例子来描述:某个函数乘坐电梯去上班,快关电梯门的时候发现了同事也来了,于是按住开关放同事进来。假设此时是上班高峰,同事络绎不绝的来乘电梯,而电梯足够大。那么在这一段时间内,电梯都不会启动,直到电梯门关上。

下图示中 X是一个被 debounce 的函数实际执行的时机

|||||||||||||||||||||||| (pause) ||||||||||||||||||||||||
                        X                                 X

常见的使用场景:

  • toggling state
  • until scroll end 事件
  • until mouse move end 事件
  • until typing end 事件
  • 触发 Ajax 请求的 event

基于幂等的考虑,需要将一段时间内的所有事件收束为一个事件,可以使用 debounce

实现

debounce = function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;

var later = function() {
timeout = null;
func.apply(context, args);
};

clearTimeout(timeout);
timeout = setTimeout(later, wait);

};
};

参考

可视化demo