高频DOM事件需用去抖或节流优化:去抖在连续触发结束后延时执行一次,适用于搜索输入、表单校验等关注最终状态的场景;节流则按固定间隔执行,适用于滚动监听、拖拽绘制等需过程反馈的场景。
高频 dom 事件(如 scroll、resize、mousemove、input)容易在短时间内被反复触发,若每次触发都执行复杂逻辑(比如重排、请求、计算),会导致页面卡顿、资源浪费甚至崩溃。函数去抖(debounce)和节流(throttle)就是专为这类问题设计的轻量级控制策略——它们不阻止事件发生,而是智能调度回调的执行时机。
去抖:等用户“停下来”再响应
去抖适用于关注最终状态的场景。它让函数只在事件连续触发结束后,等待一段空闲时间才执行一次。期间任何新触发都会重置倒计时。
-
核心逻辑:用
setTimeout+clearTimeout实现。每次触发时清除旧定时器,新建一个;只有当“静默期”完整过去,函数才真正运行。 -
典型用途:
- 搜索框输入联想(等用户打完字再发请求)
- 表单实时校验(避免每输一个字就报错)
- 窗口缩放后重新布局(等用户调好尺寸再重绘)
- 注意点:如果用户持续操作(比如一直滚动或输入),回调永远不会执行——这正是它的设计目的,不是 bug。
节流:固定节奏,匀速响应
节流适用于需要过程中持续反馈、但又不能太频繁的场景。它保证函数在单位时间内最多执行一次,不管事件触发多少次。
-
核心逻辑:常用两种实现方式:
– 时间戳法:记录上一次执行时间,当前时间减去它 ≥ 间隔才执行并更新时间戳;
– 定时器法:用标志位(如timeout)锁住执行通道,首次触发设定时器,到期才清空标志并允许下一次。 -
典型用途:
- 滚动监听判断是否触底加载(需定期检查,不能只等停)
- 鼠标拖拽/画布绘制(保持视觉连贯,又不压垮渲染)
- 抢购按钮防重复点击(限制提交频率,而非禁止所有点击)
- 注意点:节流不保证“第一次触发立即执行”,默认是延迟执行;如需首屏立刻响应(前导执行),需额外加判断逻辑。
怎么选?看业务要的是“结果”还是“过程”
一句话判断:
– 如果你只关心用户操作结束后的那个状态(比如最终输入内容、最终窗口大小),选 去抖;
– 如果你需要在操作过程中定期获取信息或反馈(比如滚动中不断计算位置、拖拽中持续更新坐标),选 节流。
- 同一个事件也可能混合使用:例如
scroll既用节流做位置监听,又用去抖做“停止后加载更多” - 实际封装时建议加上
this绑定和参数透传,避免上下文丢失 - 现代项目可优先使用 Lodash 的
_.debounce和_.throttle,它们已处理了取消、前导/尾随选项等边界情况
简单封装示例(可直接用)
去抖:
function debounce(fn, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), wait);
};
}节流(时间戳版):
function throttle(fn, delay) {
let last = 0;
return function(...args) {
const now = Date.now();
if (now - last >= delay) {
fn.apply(this, args);
last = now;
}
};
}

















