首先,这两个东西不是浏览器提供的api,也不是ECMA搞的,而是在大家通常使用中,根据实际情况而总结出来的两类函数。
debounce和throttle解决了什么问题
要说明白debounce和throttle解决了什么问题,那就要先说明debounce和throttle是什么。
从翻译软件来说,两个的的中文译名分别是去抖和节流阀,似乎很难理解。其实这两个东西都是解决同一个问题,那就是多余频繁的事件。在浏览器监听的某些事件可能在用户的实际使用的在极短的时间内密集的触发,如果这个事件对应的函数需要重新渲染界面,则会很大的消耗性能,所以可能看到画面的割裂或者抖动。
所以在很多时间我们需要合并一些可能会在短时间密集触发行为。
那么具体到debounce和throttle,分别是什么呢?
怎么写debounce和throttle
debounce
debounce可以用电梯解释,你首先进入了电梯,然后在关门之前,有人要进电梯,所以你按了开门键,随后电梯关门,进入你想去的楼层。这里你开门的行为就是debounce,电梯进去你想去的楼层就是触发的函数。
也就是说,如果一直有人进入电梯,那么这个函数就一直不会被执行,直到在规定的时间内没有新的人进入电梯,才会关门去你想去的楼层。对应的代码上就是
var debounce = function(action, delay) {
var timer = null;
return function() {
var self = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
action.apply(self, args)
}, delay);
}
}
// test
function test() {
console.log("test");
}
window.onresize = debounce(test, 300);
这里使用到了一个闭包的概念,来维持计时器timer。通过代码我们可以看到,每次window.onresize的两次触发间隔小于300ms,则重置定时器,直到两次触发的间隔大于300ms才会执行console。
throttle
对于throttle来讲,我们依旧可以拿电梯来举例,但是这次的电梯可能有点不符合常理,你依旧会看到有人进来就打开电梯门呢,但是你这次每次只打开几秒,如果这时候超过这个时候还有人想进来,那么不行。
具体到代码上
var throttle = function(action, delay){
var statTime = 0;
return function() {
var currTime = +new Date();
if (currTime - statTime > delay) {
action.apply(this, arguments);
statTime = currTime ;
}
}
}
// test
function test() {
console.log("test");
}
window.onresize = throttle(test, 300);
这个和上面的那个略有不同,依旧使用闭包维护了一个startTime,但是对于onresize是首先触发一次,然后记录这次的触发时间,在这次触发时间300毫秒以内的所有触发都置之不理。直至两次时间差超过300ms,才会执行一次触发的函数。
使用场景
debounce多数是用于键盘事件过于密集的场景,或下拉请求。
throttle则多用于一些拖动场景。