javascript中什么是防抖和节流_它们如何提升性能【教程】

12次阅读

防抖与节流是事件响应策略:防抖只执行最后一次触发(如搜索框停顿后请求),节流则按固定间隔执行(如滚动中每200ms检查位置),二者均用于避免高频无意义调用,而非直接优化CPU或内存性能。

javascript中什么是防抖和节流_它们如何提升性能【教程】

防抖和节流不是“性能优化技巧”,而是「事件响应策略」

它们不直接提升 CPU 或内存性能,而是防止函数被高频、无意义地调用——比如用户狂输 10 个字,input 事件触发 10 次,你却发了 10 次搜索请求;或者拖拽窗口时 resize 每毫秒触发几十次,你却反复重算 dom 尺寸。真正拖慢页面的,是这些本可跳过的逻辑执行,而非事件本身。

防抖:debounce(fn, delay) —— 只信“最后一击”

每次触发都清掉旧定时器,只在停止触发 delay 毫秒后执行一次。适合“结果比过程重要”的场景:

  • 搜索框联想:用户打完 “react” 停顿 300ms 后才查,中间删改都不发请求
  • 表单校验(邮箱格式):输入中不提示,光标移出或停顿时再验
  • 按钮防重复提交:点击后立刻禁用 + 防抖,避免双击触发两次 API

⚠️ 容易踩的坑:

  • debounce 返回的是新函数,不能在 addEventListener 里每次写 debounce(handleInput, 300),否则每次渲染都新建闭包clearTimeout 失效 → 必须提前定义并复用:const debouncedInput = debounce(handleInput, 300)
  • 没传 this 和参数:原始事件回调里的 this 是 DOM 元素,但防抖函数里会丢失 → 必须用 fn.apply(this, arguments) 或展开参数
  • delay 设太小(如 50ms)≈ 没防抖;设太大(如 800ms)用户会明显感知延迟 → 搜索建议推荐 200–300ms,表单校验可设 400–500ms

节流:throttle(fn, interval) —— 要“节奏感”,不要“全漏掉”

保证函数至少每 interval 毫秒执行一次,不管触发多密。适合“需要感知过程但不能太密”的交互:

立即学习Java免费学习笔记(深入)”;

  • scroll 监听吸顶或懒加载:滚动中每 200ms 检查一次 scrollTop,既不卡顿也不错过关键位置
  • 鼠标拖拽更新坐标:canvas 绘图、自定义 slider,不需要每帧都算,16ms(60fps)或 50ms 更合理
  • mousemove 实时预览:避免鼠标划过时疯狂重绘缩略图

⚠️ 容易踩的坑:

  • 时间戳版(推荐)首次立即执行,但若需“首次也等间隔”,得用定时器版(带 leading/trailing 控制)
  • 别把 interval 设成 0 或负数 —— 会导致无限循环或不执行
  • vue/react 中,别在 renderuseEffect 里动态生成节流函数,同样会破坏引用稳定性 → 应提至组件外或用 useCallback 缓存

选错就等于交互逻辑错:防抖 vs 节流,本质是业务语义问题

不是“哪个更快”,而是“你要响应什么”:

  • 用户 resize 窗口:用防抖 —— 等他拖完再重排布局,稳
  • 用户 scroll 页面想实时显示“已滚动高度百分比”:用节流 —— 防抖会卡住不动,直到他停手,体验断层
  • 游戏里按空格射击:用节流(interval=200ms)限制射速,不是防抖 —— 防抖会让连按变单发,节流才能实现“每 200ms 最多一发”的节奏

真实项目中,lodash_.debounce_.throttle 已处理取消、立即执行、this 绑定等边界,比手写更可靠;但前提是理解它们为何这样设计 —— 否则连配置项都看不懂,比如 leading: true 是啥意思,maxWait 解决什么问题。

text=ZqhQzanResources