如何理解debounce和throttle?
前端工程师们都听过看起来很高级的词,节流和防抖,其实节流就是debounce,防抖就是throttle,其实这个也属于前端性能优化的一部分。
在做远程搜索时,如果每输入1个字就调用1次接口,就会频繁查询数据库,假设我们的查询是"一二三四五",不考虑用户输入错误的情况,至少会请求5次。
- 有没有一种方法,可以隔个几百毫秒再去查询呢?
- 有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?
有没有一种方法,可以隔个几百毫秒再去查询呢?
有,可以为函数设置一个setTimeout函数,相当于定时调用接口,这种方法是低效的,也是非常愚蠢的,需要控制开关定时器,一旦搜索功能多了,就更蠢了。
有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?
有,debounce就是做这个事情的,lodash从0.1.0就支持了这个方法。
css-tricks的lodash debounce demo
<input type="text" class="autocomplete">
// 被debounce的函数,http请求,事件处理函数等等
function make_ajax_request(){
// 这是一个调用后端api的方法
}
// 监听事件并且调用lodash的debounce方法
$('.autocomplete').on('keydown',
_.debounce(make_ajax_request, 1300));
});
vue项目中的lodash debounce demo
<template>
<input @input="debounceHandleInput"/>
</template>
<script>
import _ from 'lodash';
export default {
name: 'debounce',
data() {
return {
starTime: 0,
endTime: 0,
delay: 1000,
};
},
computed: {
debounceHandleInput() {
return _.debounce(this.handleInput, this.delay);
},
},
methods: {
handleInput(e) {
console.log(`debounce wait时间为${this.delay}ms`);
console.log('触发了input事件', e.target.value);
this.startTime = new Date().getTime();
this.remoteMethod();
},
remoteMethod() {
setTimeout(() => {
const result = `后端请求已完成!`;
this.endTime = new Date().getTime();
const costTime = this.endTime - this.startTime;
console.log(result);
console.log(`耗时${costTime}毫秒`);
}, 2000);
},
},
};
</script>
打印结果:
debounce wait时间为1000ms
触发了input事件 13131
后端请求已完成!
耗时2000毫秒
在1000ms时间范围内触发,仅仅调用一次remoteMethod,也就是仅仅调用一次后端接口,达到我们的预期效果。
debounce适用场景
- Debouncing a input event handler (this example explain this use case)
- Debouncing a resize event handler
- Debouncing a save function in an autosave feature
在做滚动加载时,如果用户滚动的幅度过大,会导致加载的内容过多,相当于水的流量没有控制,一瞬间大量的水量迸发而出,从而所看到的延后好几个与预期的下一个不符的情况
- 当水流超过阀值时,最多释放出阀值量的水;水流小于阀值时,一切正常。有没有一种办法去控制水流的大小?
有,throttle就是做这个事情的,lodash从0.1.0也支持了这个方法。
具体demo就不写了,因为throttle常用于连续事件的事件处理函数。
可以参考 https://css-tricks.com/the-difference-between-throttling-and-debouncing/ 文章最后的demo,其中的throttle在scroll上的运用,就是throttle的正确打开方式。
imagethrottle适用场景
- Throttling a scroll event in infinite scroll(demo case)
- Throttling a mousemove/touchmove event handler in canvas
debounce和throttle的对比
地址:http://demo.nimius.net/debounce_throttle/
图片:
通过在canvas上连续触发mousemove事件我们发现:
- debounce只有当连续事件停止后的一小段时间后再触发一次,连续事件结束后可能只触发一次
- throttle会在连续事件的过程中,每隔一段时间至少触发一次,连续事件结束后触发不止一次
努力成为一个不掉队的前端工程师!