标准答案

  1. 防抖 debounce 的核心是每次触发都清掉旧定时器,重新计时。
  2. 节流 throttle 的核心是在一段时间内限制执行频率,可以用时间戳或定时器实现。
  3. 防抖更关注“最后一次”,节流更关注“固定频率”。
  4. 实现时要保留 this 和参数,否则包装后的函数在对象方法或事件回调里可能行为不对。
  5. 完整实现还可以支持立即执行、取消执行、尾部执行等选项。

题目解析

这两个函数解决的都是高频触发,但业务含义不一样。搜索框输入时,用户还在打字,中间状态通常没必要请求,所以适合防抖;滚动监听需要持续得到位置变化,只是不能太频繁,所以更适合节流。

手写实现不能只背 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 和参数。
  • 把防抖用于需要连续反馈的滚动进度,导致交互明显滞后。
  • 组件卸载或页面离开时没有清理未执行的定时器。

作者信息