防抖与节流
1. 概念与区别
(1) 防抖
定义:在事件被触发 delay 毫秒后才执行。如果在该时间内再次触发,则重新计时。
场景:
- 用户在输入框搜索(停止输入后再发请求)。
- 自动保存(停止编辑后再保存)。
- 窗口调整
resize(调整过程中不计算,停止后计算)。
核心思想:对于连续的事件,只执行最后一次。
(2) 节流
定义:规定在单位时间内(如 1 秒)只能触发一次。如果该时间内被触发多次,只有一次生效。
场景:
- 滚动条
scroll监听(可设置每 100ms 计算一次位置)。 - 按钮防止重复点击。
核心思想:对于连续的事件,稀释执行频率(每隔多少时间执行一次)。
2. 手写防抖与节流
面试时,不仅需要说出区别,更需要现场手写代码。
(1) 手写防抖
(2) 手写节流
这里提供两种方案:时间戳版(立即执行,但在最后一次后不会再执行)和 定时器版(延迟执行,但在最后一次后会补执行)。面试写出简单版即可。
组合版 (推荐):
3. 防抖在 AI 对话框中的应用
场景:用户停止输入后再请求辅助能力
AI 对话框中,用户每输入一个字符都会触发 input 事件。如果每次输入都请求服务端,容易产生大量无效请求,并且会让旧请求和新请求同时返回,造成提示内容闪烁或覆盖。
防抖适合处理“用户停止输入后再执行”的任务,例如:
- 生成 Prompt 补全或问题建议。
- 根据输入内容匹配历史问题、知识库或指令模板。
- 停止编辑后自动保存草稿。
- 停止输入后计算 Token 数量、上下文长度和费用预估。
但“发送消息”通常不应该使用防抖。用户点击发送后应立即提交,重复发送应通过按钮禁用、请求状态或幂等键处理。
实现:防抖 + 取消旧请求
为什么要取消旧请求?
仅使用 setTimeout 只能减少请求次数,不能处理已经发出的请求。例如:
使用 AbortController 可以在新输入到来时取消旧请求。即使某些服务端已经处理了旧请求,前端也不会再使用被取消请求的结果。对于无法取消的请求,还应增加请求序列号,只接受最后一次请求的响应。
参数选择与注意事项
- 防抖时间通常取
300~500ms:太短会产生较多请求,太长会让输入体验变差。 - 处理输入法时,要关注
compositionstart和compositionend,避免中文输入过程中间状态触发请求。 - 流式输出不适合用防抖控制每个 Token 的渲染,可以使用节流或批量刷新,保证界面流畅。
- 草稿自动保存可以使用更长的防抖时间,例如
800~1500ms,并在页面离开前再主动保存一次。 - 请求接口应设置超时、重试策略和鉴权;发送消息等非幂等操作不能仅靠防抖防重复。
4. 面试考点
- this 指向问题:回调函数必须使用
function关键字或者箭头函数通过apply绑定正确的this。 - 参数透传:使用
...args并通过apply传递给原函数。 - 立即执行:防抖和节流都可以通过
immediate选项控制首次是否立即触发。 - 取消功能:在返回的函数上挂载
.cancel()方法清除定时器。
5. 总结
- 防抖:最后一次说了算。(输入框搜索)
- 节流:按节奏执行。(滚动监听)

