




防抖与节流是事件响应策略:防抖只执行最后一次触发(如搜索框停顿后请求),节流则按固定间隔执行(如滚动中每200ms检查位置),二者均用于避免高频无意义调用,而非直接优化CPU或内存性能。
它们不直接提升 CPU 或内存性能,而是防止函数被高频、无意义地调用——比如用户狂输 10 个字,input 事件触发 10 次,你却发了 10 次搜索请求;或者拖拽窗口时 resize 每毫秒触发几十次,你却反复重算 DOM 尺寸。真正拖慢页面的,是这些本可跳过的逻辑执行,而非事件本身。
debounce(fn, delay) —— 只信“最后一击”每次触发都清掉旧定时器,只在停止触发 delay 毫秒后执行一次。适合“结果比过程重要”的场景:
⚠️ 容易踩的坑:
debounce 返回的是新函数,不能在 addEventListener 里每次写 debounce(handleInput, 300),否则每次渲染都新建闭包,clearTimeout 失效 → 必须提前定义并复用:const debouncedInput = debounce(handleInput, 300)
this 和参数:原始事件回调里的 this 是 DOM 元素,但防抖函数里会丢失 → 必须用 fn.apply(this, arguments) 或展开参数delay 设太小(如 50ms)≈ 没防抖;设太大(如 800ms)用户会明显感知延迟 → 搜索建议推荐 200–300ms,表单校验可设 400–500msthro
ttle(fn, interval) —— 要“节奏感”,不要“全漏掉”保证函数至少每 interval 毫秒执行一次,不管触发多密。适合“需要感知过程但不能太密”的交互:
scroll 监听吸顶或懒加载:滚动中每 200ms 检查一次 scrollTop,既不卡顿也不错过关键位置mousemove 实时预览:避免鼠标划过时疯狂重绘缩略图⚠️ 容易踩的坑:
leading/trailing 控制)interval 设成 0 或负数 —— 会导致无限循环或不执行render 或 useEffect 里动态生成节流函数,同样会破坏引用稳定性 → 应提至组件外或用 useCallback 缓存不是“哪个更快”,而是“你要响应什么”:
interval=200ms)限制射速,不是防抖 —— 防抖会让连按变单发,节流才能实现“每 200ms 最多一发”的节奏真实项目中,lodash 的 _.debounce 和 _.throttle 已处理取消、立即执行、this 绑定等边界,比手写更可靠;但前提是理解它们为何这样设计 —— 否则连配置项都看不懂,比如 leading: true 是啥意思,maxWait 解决什么问题。