手写防抖debounce
应用场景
当需要在事件频繁触发时,只执行最后一次操作,可以使用防抖函数来控制函数的执行频率,比如窗口resize事件和输入框input事件;
这段代码定义了一个名为 debounce
的函数,它接收两个参数:fn
(一个需要被防抖处理的函数)和 delay
(一个延迟时间,单位是毫秒)。防抖(debounce)技术的主要目的是限制某个函数在一定时间内只执行一次,即使在这段时间内被频繁调用。这对于优化性能特别有用,比如避免因快速连续触发事件(如窗口调整大小、输入验证等)而造成的不必要的计算或 DOM 操作。
下面是代码的逐行解析:
let timer = null;
:在这个函数作用域内声明一个变量timer
,并初始化为null
。这个变量将用来存储 setTimeout 的返回值,即一个可以被清除的计时器标识。return function () { ... };
:debounce
函数返回一个新的匿名函数。这样做是因为我们希望返回一个经过防抖处理的新函数,而不是直接修改原函数。这种设计模式称为“闭包”,返回的函数能够访问外部函数(debounce
)中的局部变量,如timer
。if (timer) clearTimeout(timer);
:每次新的返回函数被调用时,首先检查timer
是否存在且不为null
。如果存在,这意味着之前已经设置了一个定时器但尚未执行。此时,通过clearTimeout
清除这个定时器,从而取消即将执行的fn
调用。timer = setTimeout(() => { fn.apply(this, arguments); }, delay);
:这里设置一个新的定时器。当过了delay
毫秒后,内部的箭头函数会被执行,它通过apply
方法调用原始函数fn
,并确保this
的上下文以及传给防抖函数的所有参数都能正确传递给fn
。apply
的第一个参数this
保证了在fn
被调用时能保留正确的上下文环境,特别是当fn
是对象的方法时;第二个参数arguments
是一个类数组对象,包含了所有传入的参数。
function debounce(fn, delay) {
let timer = null;
return function () {
如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) clearTimeout(timer);
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="myInput">
<div id="display"></div>
</body>
<script>
// 假设这是你的去抖动函数
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
// 这是你想要在输入框内容变化时执行的函数
function updateContent(event) {
// 获取输入框的值
const inputValue = event.target.value;
// 更新某个元素的内容(例如,一个显示框)
displayElement.textContent = inputValue;
}
// 获取输入框和显示框的元素
const inputElement = document.getElementById('myInput');
const displayElement = document.getElementById('display');
// 为输入框绑定事件监听器,并使用去抖动函数
//将返回的函数绑定到相应的事件处理程序上,以实现防抖的效果。
inputElement.addEventListener('input', debounce(updateContent, 500)); // 延迟500毫秒
</script>
</html>
展示
function debounce(fn,delay){
let timer=null;
return function(){
if(timer) clearTimeout(timer);
timer=setTimeout(()=>fn.apply(this,arguments),delay)
}
}