防抖和节流需按场景灵活配置:防抖须支持立即执行、手动取消及this/参数保留;节流宜融合时间戳与定时器,独立控制首尾执行;兼容ie11需避免es6语法;建议按需提供debounceonce、throttleleading等组合函数。

防抖和节流不是“写一次就能到处用”的通用函数,而是需要按场景灵活配置的工具。关键不在代码多短,而在是否支持取消、是否保留 this 和参数、是否兼容低版本环境、是否能应对首次/末次执行需求。
防抖函数:支持立即执行与手动取消
基础防抖常被忽略两个重点:一是用户快速输入后突然点击搜索按钮,需立刻触发;二是组件卸载时必须清除定时器,否则造成内存泄漏。
- 用 闭包变量 timer 存储定时器 ID,每次触发先 clearTimeout
- 设置 immediate 参数控制首次是否立即执行(如搜索框旁的「搜索」按钮点击需立刻响应)
- 返回函数上挂载 cancel 方法,供外部主动终止待执行逻辑(Vue 的 beforeUnmount / React 的 useEffect cleanup 中调用)
节流函数:时间戳 + 定时器双策略融合
纯时间戳版节流在事件停止后不再执行,纯定时器版可能首次延迟过久。真实业务中,滚动加载需要“滚动开始就检查一次,之后每 200ms 检查一次,结束前再补一次”。
- 记录上一次执行时间 lastTime,用时间差判断是否可执行(保障节奏)
- 同时维护 timer,在最后一次触发后兜底执行(避免“永远不触发末次”)
- 将 leading(首次执行) 和 trailing(末次执行) 设为独立开关,按需开启
兼容性处理:不依赖 ES6+ 特性
面向企业级项目,仍需支持 IE11 或部分国产浏览器内核。避免使用箭头函数、剩余参数、解构赋值等语法。
- 用 arguments 替代 ...args,手动转数组再 apply
- this 指向统一用 var context = this 显式绑定
- 定时器清除统一用 window.clearTimeout,避免局部作用域问题
- 导出方式适配 AMD/CJS/ESM,例如用 typeof module !== 'undefined' 判断环境
业务封装建议:按需导出组合函数
不要只暴露一个 debounce 和一个 throttle。实际开发中,90% 的搜索用「延迟执行 + 可取消」,80% 的滚动监听用「首尾都执行 + 200ms 间隔」。
- 提供 debounceOnce:只允许注册一次,重复调用自动忽略(适合全局配置初始化)
- 提供 throttleLeading 和 throttleTrailing 独立版本,减少条件判断开销
- 提供 debounceWithCancel 工厂函数,返回 { fn, cancel } 对象,便于 Vue 或 React Hook 管理生命周期











