贝利信息

什么是防抖和节流_如何优化事件处理性能【教程】

日期:2026-01-24 00:00 / 作者:幻影之瞳
防抖是“等停手再执行”,节流是“保底节奏”;防抖适用于只关心最终值的场景,节流适用于必须响应过程的场景;二者均需正确清除定时器、绑定this、独立实例化,且返回新函数须赋值使用。

防抖 debounce:不是“延迟执行”,而是“等停手再执行”

防抖不是简单加个 setTimeout 就完事——它本质是「取消重来」的策略。用户连续输入、拖拽或缩放窗口时,你并不需要每一下都响应,而是只关心他最终停下来那一刻的状态。

常见错误现象:
• 搜索框输完立刻发请求,但用户还在打字,结果发了 5 次请求,后 4 次全白费
resize 监听里直接查 DOM 宽高,页面卡顿甚至崩溃
• 定时器没清干净,导致旧回调在新逻辑之后执行,数据错乱

节流 throttle:不是“限制次数”,而是“保底节奏”

节流适用于那些你必须「过程中响应」的场景,比如滚动定位、鼠标轨迹、Canvas 动画。它不等用户停下,而是强制让回调按固定节奏跑——哪怕用户狂滚 1 秒,你也只执行 10 次(假设间隔 100ms)。

常见错误现象:
• 纯时间戳版 throttle 在用户快速滚动到底部后突然停下,最后位置没更新(漏掉结尾)
• 纯定时器版堆起多个未执行任务,松手后连发几下,体验断续
• 多个元素共用同一个 throttle 函数,计时互相干扰(比如两个滚动容器抢同一个 lastCall

选错就白优化:debounce vs throttle 的关键决策点

这不是性能“银弹”,选错反而更糟——比如用 debounce 做滚动加载,用户已经划过“加载更多”区域才发起请求;用 throttle 做搜索联想,用户停手后还继续发前几次的请求,浪费带宽又返回过期结果。

实际部署时最易忽略的一件事

防抖和节流函数返回的是**新函数**,必须赋值后绑定到事件上,不能直接调用。写成 window.addEventListener('scroll', throttle(handleScroll, 100)()) 是错的——多了一对括号,等于立即执行并返回 undefined

还有:它们不解决回调函数本身低效的问题。如果 handleScroll 里反复 document.querySelector 或强制同步布局,再好的节流也救不了。先优化函数体,再套控制层。