17370845950

函数节流:防抖与节流实现方案
函数防抖与节流均可优化高频事件性能;防抖通过延迟执行并重置定时器,确保连续触发时只执行最后一次或首次;节流则通过时间戳或定时器控制函数固定频率执行,保证周期性响应;两者分别适用于搜索输入、按钮点击与滚动监听、窗口缩放等场景。

在处理高频触发事件时,比如窗口滚动、调整大小或输入框输入,直接执行回调会导致性能问题。函数节流和防抖是两种常用的优化手段,控制函数执行频率,提升页面响应速度与用户体验。

函数防抖(Debounce)

防抖的思路是:当事件被触发后,延迟一段时间执行回调,如果在这段时间内再次触发该事件,则重新计时。

适用于搜索建议、按钮重复点击等场景,只关心“最后一次操作”。

实现方式:
  • 使用 setTimeout 缓存定时器
  • 每次触发时清除旧定时器,重新设置
  • 延迟结束后执行目标函数

基础防抖实现:

function debounce(func, wait) {
  let timeout;
  return function(...args) {
    const context = this;
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(context, args), wait);
  };
}

若需立即执行首次调用(leading edge),可加入 immediate 参数控制:

function debounce(func, wait, immediate) {
  let timeout;
  return function(...args) {
    const context = this;
    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      timeout = null;
      if (!immediate) func.apply(context, args);
    }, wait);
    if (callNow) func.apply(context, args);
  };
}

函数节流(Throttle)

节流的逻辑是:规定一个单位时间,在这个时间内最多只执行一次函数。无论触发多少次,都按固定节奏执行。

适合用于 scroll、resize、mousemove 等持续触发但只需周期性响应的场景。

实现方式:
  • 记录上一次函数执行的时间戳
  • 每次触发时判断当前时间是否超过设定间隔
  • 满足条件则执行并更新时间戳

基于时间戳的节流实现:

function throttle(func, wait) {
  let previous = 0;
  return function(...args) {
    const now = Date.now();
    const context = this;
    if (now - previous > wait) {
      func.apply(context, args);
      previous = now;
    }
  };
}

也可以使用定时器方式实现,更灵活地控制首尾执行时机:

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

防抖与节流的核心区别

理解两者差异有助于正确选择使用场景:

  • 防抖:频繁触发下只执行最后一次(或第一次),中间的都被取消
  • 节流:保证在指定时间间隔内至少执行一次,形成稳定频率

举个例子:用户连续快速滚动页面

  • 用防抖,可能在整个滚动结束才执行一次处理
  • 用节流,每100ms执行一次,能及时响应又不至于太频繁

基本上就这些,根据业务需求选择合适方案即可。