问题定义

在 Web 开发中,有些事件会频繁触发,例如:

  • window.resize:窗口大小改变时触发。
  • scroll:滚动条滚动时触发。
  • mousemove:鼠标移动时触发。
  • input:输入框内容改变时触发。

如果我们在这些事件的回调函数中执行一些耗时的操作,例如发送 AJAX 请求、更新 DOM 等,会导致页面卡顿,影响用户体验。

防抖和节流就是为了解决这个问题,它们可以限制函数的执行频率,提高页面性能。

步骤与流程

1. 防抖 (Debounce)

防抖是指在事件被触发后,延迟一段时间后再执行回调函数。 如果在这段时间内事件再次被触发,则重新计时。 只有当事件停止触发一段时间后,回调函数才会执行。

步骤:

  1. 定义一个函数,该函数返回一个闭包。
  2. 在闭包中,使用 setTimeout 设置一个定时器,延迟执行回调函数。
  3. 如果事件再次被触发,则清除之前的定时器,重新设置定时器。
  4. 只有当事件停止触发一段时间后,定时器才会执行,回调函数才会执行。

代码示例:

function debounce(func, delay) {
  let timer = null;
  return function(...args) {
    const context = this;
    clearTimeout(timer);
    timer = setTimeout(function() {
      func.apply(context, args);
    }, delay);
  }
}

2. 节流 (Throttle)

节流是指在一段时间内,只允许回调函数执行一次。 如果在这段时间内事件被触发多次,只有第一次触发会执行回调函数,其他的触发会被忽略。

步骤:

  1. 定义一个函数,该函数返回一个闭包。
  2. 在闭包中,使用 setTimeout 设置一个定时器,在定时器执行期间,禁止回调函数再次执行。
  3. 只有当定时器执行完毕后,才能再次执行回调函数。

代码示例:

function throttle(func, delay) {
  let timer = null;
  return function(...args) {
    const context = this;
    if (!timer) {
      timer = setTimeout(function() {
        func.apply(context, args);
        timer = null;
      }, delay);
    }
  }
}

工具与资源

  • setTimeout:用于设置定时器。
  • clearTimeout:用于清除定时器。

注意事项

  • 防抖和节流的 this 指向:需要使用 applycall 改变 this 指向。
  • 防抖和节流的参数:需要使用 arguments 获取参数。
  • 防抖和节流的应用场景: - 防抖适用于只需要执行一次的场景,例如搜索框输入完成后发送 AJAX 请求。 - 节流适用于需要定期执行的场景,例如滚动条滚动时更新页面内容。

参考资料