防抖和节流是优化高频事件性能的核心手段:防抖适用于“稳定后执行”,如搜索联想;节流适用于“持续但限频反馈”,如滚动监听;选择依据是业务意图而非事件类型,需注意this绑定、内存泄漏及delay合理设置。

防抖和节流是应对高频事件(如 scroll、resize、input)导致页面卡顿的核心手段。它们不增加功能,但能显著减少无效执行——不是让函数跑得更快,而是让它少跑很多次。
防抖:适合“等稳定后再动作”的场景
用户输入搜索词时,每敲一个字都发请求?显然浪费。防抖把连续触发“压缩”成一次,只在最后一次操作结束后延迟执行。
- 典型用法:搜索框联想、表单校验、按钮防重复点击
- 关键逻辑:每次触发都清除旧定时器,重设新定时器
- 基础实现只需几行:
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}; - 进阶可加立即执行(首次触发立刻运行)、取消方法(
debounced.cancel())
节流:适合“持续反馈但不能太密”的场景
滚动监听要实时获取位置,但每毫秒都执行一次毫无必要。节流确保函数至少间隔一定时间才执行一次,像匀速滴答的钟表。
- 典型用法:滚动加载、实时位置计算、canvas 动画帧控制
- 关键逻辑:用时间戳或定时器标记“上次执行时间”,未到间隔则跳过
- 推荐使用时间戳+定时器结合的“完美版”:
const throttle = (fn, delay) => {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= delay) {
fn(...args);
last = now;
}
};
}; - 注意:单纯用
setTimeout节流可能丢失中间触发,时间戳方案更可靠
怎么选?看事件意图而不是事件类型
别死记“input 用防抖、scroll 用节流”。真正决定因素是业务需求:
- 需要最终结果?→ 防抖(比如用户停手才查词)
- 需要过程反馈?→ 节流(比如滚动中持续更新吸顶状态)
- 不确定?先用节流观察,卡顿明显再换防抖;响应延迟明显再调小 delay 值
- 极端情况可组合:比如滚动中用节流取位置,停止后用防抖触发懒加载
实际落地要注意的细节
写对逻辑只是第一步,工程中容易忽略这些:
-
this 和参数绑定:用
fn.apply(this, args)或箭头函数 + 展开符保证上下文正确 -
内存泄漏风险:事件监听器未解绑时,防抖/节流函数闭包会持有所属 DOM 引用,记得在组件卸载时调用
cancel - delay 值不是越小越好:300ms 是输入类常见值;滚动建议 16–100ms(兼顾流畅与性能);resize 可放宽至 250ms
-
现代替代方案:部分场景可用
requestIdleCallback或 IntersectionObserver 替代手动节流,更符合浏览器调度机制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











