防抖说明
(1)防抖的目的:
当多次执行某一个动作的时候,限制函数调用的次数,节约资源。
(2)防抖的概念:
函数防抖(debounce):就是指触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间。
(3)防抖的应用场景:
连续的事件,只需触发一次回调的场景:
- 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染
- scroll
- 鼠标的mousemove ,mousehover事件
- 重复的ajax调用(会造成网络拥塞,增加服务器压力)
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求
- 对信息进行验证
被频繁触发(短时间内多次触发),不做限制的话,有可能一秒之内执行几十次、几百次。
如果在这些函数内部执行了其他函数,尤其是执行了操作 DOM 的函数(浏览器操作 DOM 是很耗费性能的),那不仅会浪费计算机资源,还会降低程序运行速度,甚至造成浏览器卡死、崩溃。这种问题显然是致命的。
防抖实现(力扣题目2627. 函数防抖 - 力扣(LeetCode))
题目:
请你编写一个函数,接收参数为另一个函数和一个以毫秒为单位的时间 t
,并返回该函数的 函数防抖 后的结果。
函数防抖 方法是一个函数,它的执行被延迟了 t
毫秒,如果在这个时间窗口内再次调用它,它的执行将被取消。你编写的防抖函数也应该接收传递的参数。
例如,假设 t = 50ms
,函数分别在 30ms
、 60ms
和 100ms
时调用。前两个函数调用将被取消,第三个函数调用将在 150ms
执行。如果改为 t = 35ms
,则第一个调用将被取消,第二个调用将在 95ms
执行,第三个调用将在 135ms
执行。
上图展示了了防抖函数是如何转换事件的。其中,每个矩形表示 100ms,反弹时间为 400ms。每种颜色代表一组不同的输入。
案例:
输入: t = 50 calls = [ {"t": 50, inputs: [1]}, {"t": 75, inputs: [2]} ] 输出:[{"t": 125, inputs: [2]}] 解释: let start = Date.now(); function log(...inputs) { console.log([Date.now() - start, inputs ]) } const dlog = debounce(log, 50); setTimeout(() => dlog(1), 50); setTimeout(() => dlog(2), 75); 第一次调用被第二次调用取消,因为第二次调用发生在 100ms 之前 第二次调用延迟 50ms,在 125ms 执行。输入为 (2)。
代码实现:
var debounce = function(fn, t) {// 要执行的函数(fn),延迟的时间(t)
var time = null;
return function(...args) {
if(time){
// 清除定时器
clearTimeout(time);
}
time = setTimeout(()=>{
fn(...args);
},t)
}
};
代码说明:
- 函数防抖需要一个 setTimeout 来辅助实现,setTimeout 延迟运行需要执行的代码。
- 多次触发,使用 clearTimeout 取消了先前通过调用 setTimeout 建立的定时器,即清除之前的延迟记录。重新计时。
- 若计时期间事件没有被重新触发,等延迟时间计时完毕,则执行目标代码。
防抖的 “立即执行版” 和 “非立即执行版”
函数防抖其实是分为 “立即执行版” 和 “立即执行版” 的。
- 立即执行版就是 触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- “非立即执行版” 指的是 触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
// 立即执行版函数
function debounce(fn,t){
let timer = null;
let flag = true;
return function(){
clearTimeout(timer);
if(flag){
fn(...arguments);
flag = false;
}
timer = setTimeout(() => { flag = true },t)
}
}
// 非立即执行版函数
var debounce = function(fn, t) {// 要执行的函数(fn),延迟的时间(t)
var time = null;
return function(...args) {
if(time){
// 清除定时器
clearTimeout(time);
}
time = setTimeout(()=>{
fn(...args);
},t)
}
};