标准答案
- 防抖 debounce 的核心是每次触发都清掉旧定时器,重新计时。
- 节流 throttle 的核心是在一段时间内限制执行频率,可以用时间戳或定时器实现。
- 防抖更关注“最后一次”,节流更关注“固定频率”。
- 实现时要保留 this 和参数,否则包装后的函数在对象方法或事件回调里可能行为不对。
- 完整实现还可以支持立即执行、取消执行、尾部执行等选项。
题目解析
这两个函数解决的都是高频触发,但业务含义不一样。搜索框输入时,用户还在打字,中间状态通常没必要请求,所以适合防抖;滚动监听需要持续得到位置变化,只是不能太频繁,所以更适合节流。
手写实现不能只背 setTimeout。事件回调里经常依赖 this、event、最新参数,如果包装函数没有正确透传,表面上限流成功了,业务逻辑却会丢上下文。
实际项目还要考虑取消和组件卸载。比如页面离开时还挂着一个延迟执行的防抖回调,它可能在组件销毁后继续改状态。
代码示例
基础实现先保证延迟执行、固定频率、this 和参数透传。
JavaScript
function debounce(fn, delay) {
let timer = null
return function debounced(...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
function throttle(fn, wait) {
let lastTime = 0
return function throttled(...args) {
const now = Date.now()
if (now - lastTime >= wait) {
lastTime = now
fn.apply(this, args)
}
}
}常见误区
- 只写定时器逻辑,忘记透传 this 和参数。
- 把防抖用于需要连续反馈的滚动进度,导致交互明显滞后。
- 组件卸载或页面离开时没有清理未执行的定时器。