防抖节流:JS 中处理高频事件的最佳实践✅

85 阅读5分钟

在前端开发中,我们经常会遇到一些频繁触发的事件,比如窗口的resize、scroll,输入框的keyup,按钮的click等等。如果不对这些事件的处理函数进行限制,可能会导致函数被频繁调用,从而引发性能问题,甚至影响用户体验。而防抖(Debounce)和节流(Throttle)就是两种常用的解决这类问题的技术。

什么是防抖(Debounce)

防抖的核心思想是:当事件被触发后,不会立即执行处理函数,而是等待一段时间。如果在这段时间内事件再次被触发,则重新开始计时,直到等待时间结束后,才会执行处理函数

举个生活中的例子,就像我们乘坐电梯,当有人进入电梯后,电梯不会马上关门,而是会等待几秒。如果在这几秒内又有人进入电梯,电梯会重新开始等待,直到没有人再进入,电梯才会关门。

下面是一个简单的防抖函数实现:

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

在这个实现中,我们使用了一个定时器timer来记录等待时间。当事件被触发时,我们先清除之前的定时器,然后重新设置一个新的定时器。这样,只要事件在delay时间内被再次触发,就会重新计时,只有当事件停止触发delay时间后,fn才会被执行。

什么是节流(Throttle)

节流的核心思想是:在一定时间内,只能执行一次处理函数。如果在这段时间内事件多次被触发,只有第一次(或最后一次)会生效,其他的触发会被忽略

同样举个生活中的例子,就像水龙头滴水,无论我们怎么打开水龙头,它都会按照固定的频率滴水,不会因为我们频繁操作而改变滴水的频率。

下面是一个简单的节流函数实现(时间戳方式):

function throttle(fn, interval) {
  let lastTime = 0;
  return function(...args) {
    const nowTime = Date.now();
    if (nowTime - lastTime >= interval) {
      fn.apply(this, args);
      lastTime = nowTime;
    }
  };
}

在这个实现中,我们通过记录上一次函数执行的时间lastTime,当事件被触发时,计算当前时间与lastTime的差值,如果差值大于等于interval,则执行fn,并更新lastTime为当前时间。这样就保证了在interval时间内,fn最多只能执行一次。

防抖与节流的区别

防抖和节流都可以用来限制函数的执行频率,但它们的侧重点不同:

  • 触发方式不同:防抖是在事件停止触发一段时间后才执行函数;而节流是在固定的时间间隔内只执行一次函数。
  • 应用场景不同:防抖更适合处理那些需要等待用户操作完成后再执行的场景,比如搜索输入框的联想功能;节流更适合处理那些需要按照一定频率执行的场景,比如滚动加载更多数据。
  • 执行次数不同:在事件频繁触发的情况下,防抖可能只会执行一次函数(如果事件一直被触发,则永远不会执行);而节流会按照固定的时间间隔多次执行函数。

防抖与节流的应用场景

防抖的应用场景

  1. 搜索输入框联想:当用户在搜索框中输入内容时,我们不需要每次输入都发送请求去获取联想结果,而是等用户停止输入一段时间后再发送请求,这样可以减少请求次数,减轻服务器压力。
  1. 表单提交按钮:为了防止用户多次点击提交按钮导致表单重复提交,我们可以使用防抖,让按钮在点击一次后,等待一段时间才能再次点击。
  1. 窗口大小调整:当窗口大小发生变化时,resize事件会频繁触发,如果我们在resize事件的处理函数中做一些复杂的计算或 DOM 操作,可能会影响页面性能。使用防抖可以让这些操作在窗口停止调整后再执行。

节流的应用场景

  1. 滚动加载更多:当用户滚动页面时,scroll事件会频繁触发。我们可以使用节流,让滚动加载更多数据的函数每隔一定时间执行一次,而不是每次滚动都执行,这样可以避免频繁请求数据。
  1. 鼠标移动跟踪:在一些需要跟踪鼠标位置的场景中,mousemove事件会频繁触发。使用节流可以限制跟踪函数的执行频率,提高性能。
  1. 射击游戏中的子弹发射:在射击游戏中,玩家可能会频繁点击发射按钮,使用节流可以限制子弹发射的频率,保证游戏的公平性和流畅性。

总结

防抖和节流是前端开发中非常重要的性能优化技巧,它们可以有效地限制频繁触发事件的处理函数的执行频率,从而提升页面性能和用户体验。

防抖适合处理需要等待用户操作完成后再执行的场景,其核心是 “等待一段时间后执行,再次触发则重新计时”;节流适合处理需要按照一定频率执行的场景,其核心是 “在一定时间内只执行一次”。

在实际开发中,我们需要根据具体的业务场景选择合适的技术,有时候还可能需要结合两者的优点来实现更复杂的功能。只有深入理解它们的原理和区别,才能更好地运用它们来解决实际问题。