JavaScript 的防抖与节流:高频事件优化策略

98 阅读5分钟

在前端开发中,处理高频事件(如滚动、输入、窗口调整大小等)时,往往会出现性能瓶颈。每次事件触发时,都可能导致不必要的计算或页面更新,从而影响用户体验。为了解决这个问题,防抖(Debouncing)和节流(Throttling)是两种常用的技术,它们能够有效优化事件响应,减少浏览器的负担。


目录

  1. 什么是防抖(Debounce)

  2. 什么是节流(Throttle)

  3. 防抖与节流的区别

  4. 防抖与节流的实现方式

    • 防抖实现
    • 节流实现
  5. 防抖与节流的应用场景

  6. 优化


1. 什么是防抖(Debounce)

防抖(Debouncing) 是一种将连续触发的事件合并为一次触发的技术。其核心思想是,当某个事件连续触发时,只有最后一次事件触发后的一段时间内没有再触发,事件处理函数才会执行。如果事件在设定的时间内再次触发,计时器会重置,直到停止触发才会执行。

典型应用场景:

  • 输入框实时搜索:用户输入时,不希望每输入一个字符都发送一次请求,而是希望在用户停止输入一段时间后再进行请求。
  • 窗口调整大小:当用户调整窗口大小时,不需要频繁计算布局,而是希望在调整停止后再进行一次计算。

防抖原理:

  1. 每次事件触发时,都会清除之前的定时器。
  2. 设置新的定时器,在延迟时间后触发事件处理函数。

2. 什么是节流(Throttle)

节流(Throttling) 是另一种优化高频事件触发的技术,其核心思想是确保在一定时间内,某个事件最多只会触发一次。节流可以控制事件的执行频率,从而减少不必要的执行次数。

典型应用场景:

  • 滚动监听:在页面滚动时,如果每次滚动都触发事件,可能会导致性能问题。通过节流,确保一定时间内只触发一次事件。
  • 按钮点击防止重复提交:对于高频点击的按钮,可以通过节流技术,确保按钮在一段时间内只触发一次点击事件。

节流原理:

  1. 每次事件触发时,如果距离上次事件执行的时间超过设定的时间间隔,就执行事件处理函数。
  2. 如果时间间隔内还有事件触发,事件会被忽略,直到时间间隔过去。

3. 防抖与节流的区别

特性防抖(Debounce)节流(Throttle)
触发频率在事件结束后,事件处理函数只会执行一次在固定时间间隔内,事件处理函数会执行多次
适用场景输入框实时搜索、搜索建议、窗口调整大小等滚动事件、resize 事件、按钮点击防止重复提交等
实现方式每次触发事件时,重新设置定时器,延迟执行在固定时间间隔内控制执行频率
触发时机事件触发停止后,延迟一定时间后执行固定时间间隔内,每次触发事件都会执行一次

总结:防抖是在一段时间内只允许事件触发一次,而节流是在一定时间间隔内频繁触发的事件,也会控制执行频率,但会在间隔期内执行多次。


4. 防抖与节流的实现方式

4.1 防抖实现

防抖的基本实现方式是通过 setTimeout 来延迟执行事件处理函数。

function debounce(fn, delay) {
  let timer;
  return function(...args) {
    if (timer) clearTimeout(timer);  // 清除之前的定时器
    timer = setTimeout(() => {
      fn.apply(this, args);  // 延迟执行函数
    }, delay);
  };
}

// 使用示例
const search = debounce(function() {
  console.log("Searching...");
}, 500);

document.getElementById('searchBox').addEventListener('input', search);

4.2 节流实现

节流的基本实现方式是通过 setTimeoutDate.now() 来控制事件执行的频率。

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

// 使用示例
const scrollHandler = throttle(function() {
  console.log("Scrolling...");
}, 200);

window.addEventListener('scroll', scrollHandler);

5. 防抖与节流的应用场景

防抖:

  1. 输入框实时搜索:避免用户每输入一个字符都发送一次请求。
  2. 表单验证:防止在每个输入框修改时都进行复杂的验证。
  3. 按钮点击:避免按钮重复点击,特别是表单提交等场景。

节流:

  1. 滚动监听:避免每次滚动都触发事件,可以限制一定时间内的触发频率。
  2. 窗口调整大小:窗口尺寸改变时不需要频繁计算布局。
  3. 按钮防止多次点击:对按钮点击频繁的操作进行节流处理。

6. 优化

  • 根据场景选择使用防抖还是节流:防抖适合连续触发的事件,而节流适合对频繁触发的事件进行频率控制。
  • 合理设置延迟时间:防抖与节流的延迟时间不宜过短或过长,需要根据实际需求调整。
  • 使用 requestAnimationFrame:对于高频的事件如滚动或动画,可以使用 requestAnimationFrame 代替 setTimeoutsetInterval,提高性能。