防抖和节流是针对不同交互意图的两种控制逻辑:防抖等待用户停止后执行,适用于搜索、校验等需最终结果的场景;节流按固定频率执行,适用于滚动、拖拽等需持续反馈的场景。

防抖和节流不是“选一个用就行”的技巧,而是针对不同交互意图的两种控制逻辑。用对了,页面丝滑、请求干净;用反了,要么用户操作没响应,要么该执行的时候被吞掉。
防抖:等用户“停下来”再干活
核心是“合并连续动作,只响应最终状态”。适合那些你并不关心中间过程、只在意结果的场景。
- 典型表现:用户快速输入“react”,防抖设为300ms,不会发5次请求,而是在他停顿300ms后,只用完整的“react”查一次
- 关键机制:每次触发都清除旧定时器、重设新定时器;只有最后一次触发后的等待期结束,函数才执行
- 必须注意:如果用户一直不停(比如长按输入、持续拖拽),函数可能永远不执行——这正是它的设计目的,不是 bug
- 实用写法:支持 immediate 选项可让首次触发立即执行(如按钮点击防连点),后续再进入防抖节奏
节流:按固定节奏“匀速干活”
核心是“不管多快,我只按自己的频率来”。适合需要持续反馈、但又不能每帧都算的场景。
- 典型表现:滚动加载列表,设200ms节流,哪怕1秒滚了80次,也只在第0ms、200ms、400ms…执行三次,保证内容及时加载又不卡主线程
- 关键机制:用时间戳或定时器标记上一次执行时间,当前触发时判断是否已过间隔;过了就执行并更新时间,没过就忽略
- 必须注意:节流不会因事件持续而“憋着不干”,它保证每个时间窗口至少执行一次,避免交互失敏
- 实用写法:推荐用时间戳方案(比定时器更轻量),配合 leading/trailing 控制首尾是否执行,适配滚动监听等细节需求
怎么选?看用户动作有没有“稳定态”
一句话判断:要不要等用户彻底停下?要,就用防抖;不要,就用节流。
- 用防抖的场景:搜索框联想、表单输入校验、resize 后重新布局、防重复提交按钮
- 用节流的场景:scroll 滚动加载、mousemove 画布跟随、drag 拖拽位置上报、游戏按键检测
- 容易踩坑的点:把节流用在搜索框——用户还没打完字,请求就发出去了;把防抖用在滚动监听——用户一滚到底,加载逻辑始终不触发
工程落地建议
别从零手写,但得懂原理。项目中优先用 Lodash 的 debounce 和 throttle,它们已处理好 this 绑定、参数透传、取消(cancel)、刷新(flush)等边界情况。
- Vue / React 中:在组件挂载时创建防抖/节流函数,卸载前调用 cancel 清理定时器,避免内存泄漏
- 调试技巧:在包装函数里加 console.time/log,观察实际执行时机和次数,比猜更可靠
- 性能验证:用 Performance 面板录一段滚动或输入操作,对比优化前后 Layout / Scripting 时间占比


















