防抖技术适用于“等用户停下来再做事”的场景,通过重置定时器将多次操作合并为一次最终执行,避免资源浪费和卡顿,核心是用setTimeout/clearTimeout配合闭包保存timeout状态,确保this和参数正确传递。

防抖技术适合用在“等用户停下来再做事”的场景,比如输入搜索、调整窗口大小、表单验证等。它的关键不是压低执行次数,而是把多次操作合并成一次“最终动作”,避免资源浪费和界面卡顿。
防抖的核心逻辑:重置计时器
每次事件触发时,先清除上一次设置的定时器,再新建一个。只有当事件完全停止触发、且等待时间(如 300ms)过去后,函数才真正执行。
- 依赖 setTimeout 和 clearTimeout 控制延迟与取消
- 用闭包保存 timeout 变量,确保多次调用共享同一计时状态
- 用 func.apply(this, args) 保证原始函数的 this 和参数不丢失
一个轻量可靠的防抖函数写法
下面这个版本支持常见需求,无依赖、易理解、可直接复用:
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
- ...args 支持任意参数,比 arguments 更现代清晰
- 没加 immediate 模式,避免首次触发就执行带来的逻辑混淆(如搜索框不该一输就查)
- 返回的是新函数,可直接传给 addEventListener
典型使用示例
以搜索输入框为例,防止每打一个字就发请求:
立即学习“Java免费学习笔记(深入)”;
const searchInput = document.getElementById('search');const debouncedSearch = debounce((e) => {
fetch(`/api/search?q=${e.target.value}`)
.then(res => res.json())
.then(data => renderSuggestions(data));
}, 400);
searchInput.addEventListener('input', debouncedSearch);
- 用户连续输入,中间任何一次都不会触发 fetch
- 停顿满 400ms 后,才用最后一次的 value 发起请求
- 网络请求、DOM 渲染这类耗时操作,就自然被“托住”了
要注意的细节
防抖不是万能的,用错地方反而影响体验:
- 不要在需要即时反馈的场景用,比如拖拽位置更新、滚动监听加载更多——该用节流
- wait 时间别设太长(如 >800ms),否则用户会觉得响应迟钝;也别太短(如
- 如果事件回调里用了箭头函数,注意 this 指向可能已丢失,建议显式传参或绑定上下文


















