debounce(防抖)
做项目时第一次听到这个名词,一脸蒙B。今天有时间就了解了一下这是什么概念?目的就是防止用户点击过快导致数据提交多次。
我们把时间拉长就能更好的理解,例如规定10秒内只有一次点击生效,时间从0开始点击一次,如果在1,2,3...9秒时间点上再点击是无效的,当时间大于10秒的时候,再点击就可以生效了。
网上能查到的实现原理都是使用setTimeout延时执行代码,还是上面的例子,0秒点击时启动一个定时器,10秒后生效,这不大友好,因为这是第一次点击应该马上执行。
如果第3秒又点击了一下,那么清除上面的定时器,第3+10=13秒后生效,如果一直点一直延时10秒,不大友好。
所以我改进了一下,让它真正做到规定时间间隔内执行一次代码,如果是新点击则马上执行代码,在时间间隔内连续点击则清除上一次定时器,并计算与终点时间之差启动新定时器。例如(第一次)0秒点击了一次马上执行,第5秒(第二次)点击了一次,时间差=10-5=5秒,5秒后执行代码则是第10秒。如果第25秒(第三次)点击一次也马上执行,因为上一次的时间间隔期是第20秒已经过了则为新点击。
事例代码如下
/**
* 防抖,时间间隔内只执行一次代码
* @param {Function} fn 需要防抖处理的函数
* @param {number} wait 时间间隔
* @returns
*/
function debounce(fn, wait) {
/** 上一次执行 fn 的时间 */
let previous = 0;
/** 定时器 */
let timer = null;
/** 定时器时间 */
let wait_remain = 0;
// 将 debounce 处理结果当作函数返回
return function (...args) {
// 获取当前时间,转换成时间戳,单位毫秒
let now = +new Date();
if (timer) {
clearTimeout(timer);
}
//定时器时间 = 总间隔-上次运行到现在用时
wait_remain = wait - (now - previous);
// 如果定时器时间>0则继续运行定时器
if (wait_remain > 0) {
// 定时器时间结束后执行函数 fn
timer = setTimeout(() => {
previous = +new Date();
fn.apply(this, args);
}, wait_remain);
return;
}
// 第一次执行
// 或者时间间隔超出了设定的时间间隔,执行函数 fn
previous = now
fn.apply(this, args)
}
}
//使用防抖10秒时间间隔
test = debounce(() => {
console.log(new Date());
}, 1000*10);
//每5秒运行一次
test();
setInterval(() => {
test();
}, 1000*5);