目录
- 防抖(debounce)
- 节流(throttle)
- 防抖和节流的区别
上周写了个表单,没仔细看Toast的遮罩配置,以为和之前一样都是默认开启的,然而实际上是被关了,又因为我偷懒没给按钮加防抖节流,于是出现了用户重复提交多条数据的情况…
默默掏出小本本记下仇:究竟谁关了我的遮罩按钮 一定要记得加防抖节流!!!
好了,言归正传,来复习下防抖节流。
1、防抖
防抖,debounce。这个概念最早来自于相机,现在流行的相机防抖原理也分很多种,有镜头防抖、机身防抖等,我们代码里的防抖比较类似软件防抖:
“软件会持续地监测手的抖动情况:如果你的手正在抖动,这时候即便你已经摁下了快门手机也不会进行拍照,直到它监测到你忽然有一个瞬间手是比较静止的,诶!它就自动按下了快门!所以这个并不是什么主动的防抖功能,它只是主动选择了一个’手不抖的时间’拍照。这个功能适合拍风光,不适合拍人像,因为它没有办法抓拍。”[1]
再举个生活中的防抖例子,坐过电梯的童鞋应该感受过,电梯总是要等一小段时间后再关门,如果在电梯门关上之前,又有人进入,那么电梯就会重新开门等一小段时间再关上。如果不断有人在电梯关闭前进入,电梯就会等最后一个人进来后,再等待一小段时间后才真正关门运行。
所谓防抖,就是在事件触发后延迟n秒再执行;如果在这n秒内再次触发该事件,则重新计时,延迟n秒后再执行。
代码实现:
function debounce(fn, delay) {
let timer = null;
return () = >{
if (timer) {
// 重新计时
clearTimeout(timer);
}
const context = this;
timer = setTimeout(() = >{
fn.apply(context, arguments);
clearTimeout(timer);
},
delay);
}
}
let count = 0;
const play = debounce(() = >{
console.log(count++);
},
3000);
在线运行:http://jsrun.net/Tr8Kp/edit
节流
节流,throttle。工程热力学术语释义:管道中流动的流体经过通道截面突然缩小的阀门、狭缝及孔口等部分后发生压力降低的现象称为节流。[2]
简单来讲,就是通过阀门限制实际流量。比如用户在10s内发起了1000次请求,节流控制后,实际上10s内,只有1次请求会被真正发送到服务器,其他请求都不会发出。
节流就是一段时间内,不论事件触发多少次,都只执行一次。
代码实现:
// 时间戳版本
function throttle(fn, delay) {
let isRun = false;
let startTime = Date.now();
return function() {
let now = Date.now();
if (now - startTime > delay) {
// 延迟执行
// const context = this
// fn.apply(context, arguments)
startTime = now isRun = false;
}
if (isRun) return;
isRun = true;
// 立即执行
const context = this
fn.apply(context, arguments)
}
}
let count = 0;
const play = throttle(() = >{
console.log(count++);
},
3000);
在线运行:http://jsrun.net/Wr8Kp/edit
// 定时器版本
function throttle(fn, delay) {
let timer = null
return () = >{
if (timer) return;
const context = this;
// 立即执行
fn.apply(context, arguments);
timer = setTimeout(() = >{
// 延迟执行
// fn.apply(context, arguments);
clearTimeout(timer);
timer = null;
},
delay);
}
}
let count = 0;
const play = throttle(() = >{
console.log(count++);
},
3000);
在线运行:http://jsrun.net/Lr8Kp/edit
防抖和节流的区别
看看下面这段测试代码:
let t = 0;
/** 每隔一秒点一下,一直都不会触发,除非停止自动点击 */
let interval = null;
start();
function start() {
if (!interval) {
interval = setInterval(() = >{
t++;
console.log("触发" + t + "次");
play();
},
1000);
}
}
function stop() {
console.log("点击了停止触发");
clearInterval(interval);
interval = null;
}
这段测试代码,每隔1秒会触发一次play()
方法,按照上面防抖和节流的代码,delay都是3s的话,输出结果各是什么?
防抖debounce输出结果:
节流throttle输出结果:
区别:
- 防抖因为一直不断被触发,每次触发都会重新计时,始终达不到3s的延迟,所以始终无法执行;只有在停止触发后才会执行(最后一次触发的3s后,输出count值0);
- 而节流则每隔3s执行一次;3s内可能有多次触发,但这3s内只会执行一次。
参考资料: