信息发布→ 登录 注册 退出

javascript如何实现防抖与节流_应用场景有哪些?

发布时间:2026-01-12

点击量:
防抖函数核心是每次触发清除前次定时器并重设,确保只执行最后一次;需用闭包隔离 timer、用 apply 保持 this 和参数,基础写法:function debounce(fn, delay) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; }

防抖函数怎么写?关键在 clearTimeout 和闭包

防抖的核心逻辑是:每次触发都重置定时器,只执行最后一次。常见错误是直接在全局声明 timer 变量,导致多个防抖实例互相干扰。

正确做法是用闭包保存每个实例独立的 timer

function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}
  • fn 必须能接收 apply 传入的参数,否则事件对象或输入值会丢失
  • 如果需要立即执行首次调用(leading edge),得加判断逻辑,原生实现不带这个,默认是 trailing
  • 注意 this 指向——绑定在 DOM 元素上时,fn 内部的 this 就是该元素;若需固定上下文,建议提前用 fn.bind(context)

节流函数两种主流实现:时间戳 vs 定时器

节流要保证「单位时间内最多执行一次」,但两种写法行为不同:

✅ 时间戳版(首次立即触发):

function throttleByTimestamp(fn, limit) {
  let last = 0;
  return function (...args) {
    const now = Date.now();
    if (now - last >= limit) {
      fn.apply(this, args);
      last = now;
    }
  };
}

✅ 定时器版(末次可能延迟执行):

function throttleByTimer(fn, limit) {
  let timer = null;
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(this, args);
        timer = null;
      }, limit);
    }
  };
}
  • 搜索框建议用防抖,滚动加载更多适合节流(尤其是时间戳版,用户一滚动就立刻触发请求)
  • 定时器版在连续高频触发下,最后一次调用可能被“卡住”——比如用户快速拖拽 5 秒,最后一下松手后还要等 limit 才执行
  • React 中若在函数组件里定义节流函数,要注意不要每次渲染都新建,否则 useEffect 依赖项变化会失效

实际项目中哪些地方必须加防抖/节流?

不是所有高频事件都要加,重点看是否引发副作用:

  • input 事件做实时搜索 → 必须防抖,否则每打一个字都发请求
  • resize 改变布局 → 推荐节流(如更新 canvas 尺寸、重排网格),避免重绘风暴
  • scroll 实现吸顶或懒加载 → 节流更稳妥,防抖会导致滚动停止后才计算,体验卡顿
  • 按钮重复点击提交 → 防抖 + 禁用按钮更可靠,单靠防抖不能阻止网络层重复请求
  • Canvas 动画帧驱动(如 requestAnimationFrame)→ 不要用防抖/节流,它本身就是天然节流机制

容易被忽略的边界问题

真实业务里最常踩坑的不是写法,而是上下文和清理时机:

  • Vue 组件或 React useEffect 中创建的防抖函数,组件卸载时没清除 setTimeout,会报 Can't perform a React state update on an unmounted component
  • 防抖函数被当作 onClick 处理器时,event 对象在异步回调中已失效(React 合成事件池回收),得提前用 event.persist() 或解构所需字段
  • Lodash 的 debounce 默认不执行 trailing 调用,要手动传 { trailing: true };而自己写的简易版默认就是 trailing,行为不一致容易误判
  • 移动端 touchmove 触发频率比 mousemove 高得多,同样 delay 值下更易卡顿,建议把 delay 设为 16ms(≈60fps)的整数倍
标签:# vue  # react  # javascript  # java  # 处理器  # app  # edge  # 懒加载  # ai  # 重绘  # canva  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!