前言

前前后后看了很多关于防抖和节流的文章,一直没有编程总结。防抖和节流其实比较类似,都是闭包的简单应用。前者关键在于用户频繁进行多次操作时,只响应一次;后者关键在于控制操作的频率。下次将列举出关键函数代码与实际运用例子。

防抖

防抖关键函数

1
2
3
4
5
6
7
8
9
function debounce(f, wait) {
let timmer = null;
return (...args) => {
if (timmer) clearInterval(timmer);
timmer = setTimeout(function() {
f(...args);
}, wait);
};
}

关键的两个点在于使用闭包保存timmer,以及ES6的剩余参数来传入回调函数的若干个参数。

函数调用示例

1
2
3
4
const myDebounce = debounce(myFn,1000);
for(let i=0;i<1000;i++){
myDebounce(arg1,arg2,arg3);
}

这样,即使调用1000次,也只会响应最后一次的请求。

实战说明

该例子的应用场景主要为用户频繁点击提交按钮,可能会产生多次异步请求或同步运算,这样无论对用户还是对服务器都是不友好的。因此,我们使用防抖技术,当用户频繁点击提交时,我们只响应最后一次操作。

请在下面的输入框中随机输入文本,然后疯狂点击提交按钮,只有当你停止点击2s后,你的请求才会被提交,你会看到提交成功的提示说明。

节流

节流关键函数

1
2
3
4
5
6
7
8
9
10
function throttle(f, wait) {
let timmer = null;
return (...args) => {
if (timmer) return;
timmer = setTimeout(function() {
f(...args);
timmer = null;
}, wait);
};
}

关键技术点和节流类似,只是当timmer实例已经存在时的处理方式不同。实际上仅变动了两行代码。

函数调用示例

1
2
3
4
5
6
const myThrottle = throttle(myFn,1000);
setTimeIntervar(()=>{
for(let i=0;i<4;i++){
myThrottle(arg1,arg2,arg3);
}
},500);

当间隔1s调用4次myThrottle函数时,“理论上”会执行两次回调函数。(理论上指的是事件循环无法保证一定在0.5s间隔内就执行一次定时任务也无法保证每次定时任务一定会被执行。)

实战说明

当滚动进度条时,我们不需要每次滚动事件触发就进行响应,而是间隔一定时间后响应一次,这样可以在保证用户正常体验的前提下减少性能损耗。

即使疯狂对box上下滚动,可以发现它只会间隔2s响应一次。当你停止滚动时,它有可能会再响应一次。

后记

虽然防抖和节流实现起来十分简单,但是却有很重要的地位,值得不断学习与实践。