函数防抖的核心是只执行最后一次触发,忽略中间调用,适用于搜索输入、窗口调整等场景;通过settimeout延迟执行并每次清除前次定时器实现;支持immediate参数控制首次立即执行。

函数防抖(Debounce)的核心是:**只执行最后一次触发,忽略中间的多次调用**。它适合处理“用户停止操作后才执行”的场景,比如搜索框输入、窗口大小调整、按钮重复点击等。
防抖的基本实现原理
防抖的关键在于用 setTimeout 延迟执行,并在每次新触发时清除之前的定时器。这样只有最后一次触发能“活下来”,真正执行回调。
一个简洁可靠的实现如下:
function debounce(func, wait) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
使用示例:
const handleResize = () => console.log('窗口调整完成');
const debouncedResize = debounce(handleResize, 200);
window.addEventListener('resize', debouncedResize);
带立即执行选项的增强版防抖
有些场景需要“首次触发立刻执行,后续连续触发则延迟执行最后一次”(即 leading + trailing 模式)。这时可扩展参数控制行为:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- leading: true 表示第一次触发立即执行,之后进入冷却期
- trailing: true 表示最后一次触发后延迟执行(默认行为)
- 两者都为 true 时,首次立即执行,末次延迟执行(注意可能重复)
简化版支持 leading 的写法:
function debounce(func, wait, immediate = false) {
let timeoutId;
return function(...args) {
const callNow = immediate && !timeoutId;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
timeoutId = null;
if (!immediate) func.apply(this, args);
}, wait);
if (callNow) func.apply(this, args);
};
}
如何合并频繁触发的事件
防抖本身不是“合并”事件,而是**过滤掉中间冗余触发,保留有代表性的执行时机**。所谓“合并”,实际是指:
- 把短时间内多次触发的事件,压缩成一次有效响应
- 不累积参数或状态,而是以最新一次的上下文为准(比如最新输入值、最新鼠标位置)
- 若需真正合并数据(如收集多条日志再批量上报),应配合节流或队列+定时器,而非纯防抖
例如搜索框中,用户快速输入 “hello”,触发了 h→he→hel→hell→hello 五次,防抖会丢弃前四次,只用最后一次的值("hello")发起请求。
实际应用中的注意事项
防抖函数返回的是闭包,每次调用都会生成新函数。因此绑定事件时要注意:
- 避免在 render 中反复创建防抖函数(会造成事件监听器重复绑定或无法移除)
- 推荐在组件初始化或模块顶层定义一次,再复用
- 需要手动清理时(如组件卸载),保存返回的函数引用,以便 removeEventListener
- this 指向和参数传递要明确,建议用 func.apply(this, args) 或箭头函数结合 bind 处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










