防抖和节流通过控制函数执行频次缓解主线程阻塞:防抖合并连续调用、延迟执行,适用于输入搜索等操作结束才响应的场景;节流固定间隔执行,适用于scroll等需持续感知的场景;二者均可搭配requestAnimationFrame优化动画类逻辑,并需注意内存泄漏、定时器清理及事件监听器卸载等细节。

防抖和节流通过控制函数执行频次,直接减少主线程上不必要的 JS 运行、DOM 查询、样式计算和重排重绘,从而缓解主线程阻塞。它们不改变事件触发频率,而是“过滤”或“调度”回调执行时机,让浏览器有空闲时间处理渲染与用户交互。
防抖:合并连续调用,延迟执行
适合输入搜索、窗口 resize 等“操作结束才需响应”的场景。它把密集触发压缩成一次执行,避免中间大量无效计算。
- 每次新触发都清除前一个定时器,仅保留最后一次触发后的延迟执行
- 例如输入框每敲一个字都触发 input 事件,防抖后只在用户停顿 300ms 后发起搜索请求,省去中间 5–10 次无意义的 API 调用和状态更新
- 主线程不再被反复抢占,FPS 更稳定,内存也不会因频繁创建闭包和定时器而持续增长
节流:固定间隔执行,保持节奏感
适合 scroll、mousemove 等需要“持续感知但无需实时响应”的场景。它确保函数不会太密,又不会完全丢失响应。
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 用时间戳或定时器锁定最小执行间隔,比如每 100ms 最多执行一次 handleScroll
- 滚动时即使每秒触发 120 次事件,节流后也只执行约 10 次,大幅降低 getBoundingClientRect、offsetTop 计算或 class 切换带来的重排压力
- 配合 passive: true 使用,还能避免 scroll 事件监听器强制同步执行导致的卡顿
搭配 requestAnimationFrame 进一步优化动画类逻辑
当节流/防抖用于视差滚动、滚动指示器等视觉反馈时,把最终执行包裹在 rAF 中,可让 JS 执行与屏幕刷新节奏对齐,避免掉帧。
- rAF 自动将任务排入下一帧,比 setTimeout 更精准且更节能
- 例如:节流后的 scroll 处理函数内部不直接操作 DOM,而是标记“需更新”,再由 rAF 统一读取并写入,实现读写分离
- 这样既保住了响应节奏,又把高成本操作集中在帧内可控时段完成
实际落地要注意的关键细节
光套用模板函数不够,几个易忽略点直接影响主线程收益:
- 防抖函数里别在闭包中长期持有大对象(如整个 DOM 树引用),否则引发内存泄漏
- 节流若用定时器实现,要确保 clearTimeout 及时清理,避免多个 timerId 堆积
- 对 scroll/resize 等事件,记得在组件卸载或页面离开时 removeEventListener,防止监听器残留
- 优先使用时间戳版节流(首次立即执行),比定时器版更节省 timer 资源,也更利于首屏快速响应

















