防抖函数的核心是“等用户停下来再执行”,通过延迟执行并重置计时器,确保连续操作只触发最后一次回调;支持延迟执行和首次立即执行,需注意this绑定、参数传递及定时器清理。

防抖函数的核心是“等用户停下来再执行”,不是拦截点击,而是延迟执行,并在新操作到来时重置计时器。只要实现正确,连续点击只会触发最后一次操作对应的那个请求。
防抖的基本逻辑:只响应最终的“静默”
用户快速点击时,每次点击都重置定时器,只有两次点击间隔超过设定阈值(如 300ms),才会真正发起请求。中间所有点击都被“吞掉”,不产生实际调用。
- 第一次点击 → 启动 300ms 定时器
- 第2、3、4次点击(均在300ms内)→ 清除前一个定时器,重新启动新的300ms定时器
- 最后一次点击后 300ms 内无新点击 → 定时器到期,执行回调(如发请求)
一个可靠的手写防抖函数(带立即执行可选)
以下代码支持常规防抖(延迟执行)和首次立即执行(适用于按钮防重复提交场景):
function debounce(func, wait, immediate = false) {
let timeout = null;
return function(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
}
使用示例(防止重复提交):
const handleClick = debounce(() => {
fetch('/api/submit', { method: 'POST' })
.then(res => console.log('提交成功'))
.catch(err => console.error('提交失败'));
}, 500, true); // 点击立刻执行,但500ms内重复点击被忽略
关键细节:避免 this 和参数丢失 + 清理副作用
原生 setTimeout 会丢失 this 和参数,所以必须用 func.apply(this, args);同时要确保组件卸载或事件解绑时清除定时器,防止内存泄漏或报错:
- 在 React 中,useEffect 里返回清理函数:return () => clearTimeout(timeout)
- 在 DOM 事件中,解绑前手动清除:element.removeEventListener('click', debouncedHandler)
- 不要在防抖函数内部做异步等待(如 await),它只负责控制执行时机,异步逻辑放在 func 内部处理
什么时候该用防抖?别和节流混淆
防抖适合“等用户做完再说”的场景:
- 搜索框输入(等用户打完字再请求建议)
- 窗口 resize 后重新计算布局(等用户拖完再更新)
- 按钮提交(防手抖连点,尤其配合 immediate=true)
注意:如果需要“固定频率保底执行”(比如用户一直拖拽窗口也要定期响应),那就该用节流(throttle),不是防抖。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











