防抖(Debounce)和节流(Throttle)介绍

129 阅读2分钟

防抖(Debounce)和节流(Throttle)是优化高频事件处理的两种常用技术,它们的核心目的是减少不必要的函数执行次数,提升性能。


1. 防抖(Debounce)

核心思想:事件触发后,等待一段时间内不再触发事件,才执行函数。如果在这段时间内再次触发,则重新计时。

适用场景:搜索框输入联想、窗口大小调整(resize)、文本编辑器保存。

实现代码

function debounce(func, wait, immediate = false) {
  let timeout;

  return function (...args) {
    const context = this;
    const later = () => {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };

    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

参数说明

  • func:需要防抖的函数。
  • wait:等待时间(毫秒)。
  • immediate:是否立即执行(true 表示首次触发立即执行,后续等待结束后再执行)。

简化版

// 防抖函数实现
function debounce(func, delay) {
  let timer = null;
  return function() {
    const context = this;
    const args = arguments;
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  };
}

2. 节流(Throttle)

核心思想:在一段时间内,无论事件触发多少次,函数最多执行一次。

适用场景:滚动事件(scroll)、鼠标移动(mousemove)、抢购按钮点击。

实现代码(时间戳 + 定时器)

function throttle(func, wait) {
  let lastTime = 0;
  let timeout;

  return function (...args) {
    const context = this;
    const now = Date.now();
    const remaining = wait - (now - lastTime);

    if (remaining <= 0) {
      // 时间间隔已到,立即执行
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      func.apply(context, args);
      lastTime = now;
    } else if (!timeout) {
      // 设置定时器,确保最后一次触发也能执行
      timeout = setTimeout(() => {
        func.apply(context, args);
        lastTime = Date.now();
        timeout = null;
      }, remaining);
    }
  };
}

参数说明

  • func:需要节流的函数。
  • wait:执行间隔时间(毫秒)。

简化版

// 节流函数实现
function throttle(func, delay) {
  let timer = null;
  return function() {
    const context = this;
    const args = arguments;
    if (!timer) {
      func.apply(context, args);
      timer = setTimeout(() => {
        timer = null;
      }, delay);
    }
  };
}

两者的核心区别

防抖(Debounce)节流(Throttle)
执行时机事件停止后执行固定时间间隔执行
类比电梯等人(最后一个人进后关门)地铁发车(每隔一段时间发一班)

使用示例

// 防抖:输入停止 500ms 后执行搜索
const searchInput = document.getElementById("search");
searchInput.addEventListener("input", debounce(searchHandler, 500));

// 节流:每隔 200ms 处理一次滚动事件
window.addEventListener("scroll", throttle(scrollHandler, 200));

通过合理选择防抖或节流,可以有效优化高频事件的性能表现。