标准答案
- 防抖:debounce 是事件连续触发时先不执行,等最后一次触发后经过指定时间才执行。它适合搜索输入联想、窗口 resize 后重新计算、表单校验等“只关心最终结果”的场景。
- 节流:throttle 是事件持续触发时,保证固定时间内最多执行一次。它适合滚动监听、拖拽位置更新、进度同步、埋点上报等“需要持续反馈但不能太频繁”的场景。
- 场景选择:搜索框一般用防抖,避免每输入一个字符就请求;滚动和拖拽一般用节流,保证页面持续响应;按钮提交更准确地说是防重复提交,要结合请求中状态、禁用按钮和接口幂等,而不只是套一个 debounce。
- 实现要点:手写时要保留 this 和参数,并考虑立即执行、尾部执行、取消执行等选项。工程里也可以直接使用成熟工具函数,重点是选对策略和处理边界。
题目解析
防抖和节流的区别要从“业务想要什么反馈”出发。防抖等待用户停止动作,适合最终结果;节流控制执行频率,适合持续反馈。
搜索联想用防抖,是因为用户还在输入时请求价值不高;滚动和拖拽用节流,是因为用户持续操作时仍需要阶段性更新 UI 或上报状态。
按钮提交不是简单的防抖题。真正可靠的防重复提交要结合 loading 状态、按钮禁用、请求取消、接口幂等和服务端防重。只靠前端 debounce,刷新页面或并发请求仍可能绕过。
手写实现的考点通常是 this、参数、leading、trailing、cancel。基础版本能说明核心思路即可,更完整的工程版本可以交给工具库,但要知道边界。
代码示例
下面是保留 this 和参数的核心版 debounce 与 throttle。
JavaScript
function debounce(fn, delay) {
let timer = null
return function debounced(...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
function throttle(fn, delay) {
let lastTime = 0
return function throttled(...args) {
const now = Date.now()
if (now - lastTime >= delay) {
lastTime = now
fn.apply(this, args)
}
}
}常见误区
- 把防抖和节流的触发时机说反。
- 只在前端防抖按钮提交,不处理接口幂等和请求中状态。
- 手写实现时丢失 this 和参数。