Skip to content

Latest commit

 

History

History
182 lines (155 loc) · 5.18 KB

File metadata and controls

182 lines (155 loc) · 5.18 KB

防抖(Debounce)与节流(Throttle)

一、核心原理对比

特性 防抖(Debounce) 节流(Throttle)
核心思想 "等你说完我再响应" "按固定节奏响应"
触发策略 延迟执行,期间新触发会重置计时 固定时间间隔内只执行一次
类比场景 电梯门(最后一个人进后关门) 机枪扫射(按固定频率发射)
典型应用 搜索联想、窗口 resize 结束监听 滚动加载、高频点击按钮

二、手写实现代码

1. 防抖函数(基础版 + 增强版)
function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}
/**
 * 防抖函数
 * @param {Function} fn - 目标函数
 * @param {number} delay - 延迟时间(ms)
 * @param {boolean} immediate - 是否立即执行
 * @returns {Function} 防抖处理后的函数
 */
function debounce(fn, delay = 300, immediate = false) {
  let timer = null;
  
  return function(...args) {
    const context = this;
    
    // 清除已有定时器
    if (timer) clearTimeout(timer);
    
    // 立即执行模式
    if (immediate && !timer) {
      fn.apply(context, args);
    }
    
    timer = setTimeout(() => {
      timer = null;
      if (!immediate) {
        fn.apply(context, args);
      }
    }, delay);
  };
}
2. 节流函数(时间戳 + 定时器双模式)
function throttle(func, delay) {
  let lastTime = 0;
  return function(...args) {
    const now = new Date().getTime();
    if (now - lastTime >= delay) {
      func.apply(this, args);
      lastTime = now;
    }
  };
}
/**
 * 节流函数
 * @param {Function} fn - 目标函数
 * @param {number} interval - 时间间隔(ms)
 * @param {boolean} trailing - 是否在间隔末尾执行
 * @returns {Function} 节流处理后的函数
 */
function throttle(fn, interval = 300, trailing = true) {
  let lastTime = 0;
  let timer = null;
  
  return function(...args) {
    const context = this;
    const now = Date.now();
    
    // 时间差计算
    const remaining = interval - (now - lastTime);
    
    if (remaining <= 0) {
      // 到达间隔时间立即执行
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      fn.apply(context, args);
      lastTime = now;
    } else if (trailing && !timer) {
      // 间隔末尾补发执行
      timer = setTimeout(() => {
        fn.apply(context, args);
        lastTime = Date.now();
        timer = null;
      }, remaining);
    }
  };
}

三、使用示例

// 防抖应用:搜索框联想
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function(e) {
  console.log('搜索关键词:', e.target.value);
}, 500));

// 节流应用:滚动加载
window.addEventListener('scroll', throttle(function() {
  console.log('当前滚动位置:', window.scrollY);
}, 1000));

四、实现关键点解析

功能 防抖实现要点 节流实现要点
定时器管理 每次触发重置定时器 通过时间戳判断间隔,定时器用于补发执行
上下文绑定 使用 apply 保持 this 指向正确 同上
参数传递 ...args 保留所有原始参数 同上
边缘情况处理 处理立即执行模式 处理首尾触发模式

五、高级特性扩展

  1. 取消功能

    // 防抖增加取消方法
    function debounce(...) {
      const debounced = function(...args) { ... };
      debounced.cancel = () => {
        clearTimeout(timer);
        timer = null;
      };
      return debounced;
    }
  2. 返回值处理
    (注:异步函数无法直接返回结果,可通过回调或 Promise 处理)

  3. RAF 节流

    // 使用 requestAnimationFrame 实现动画节流
    function throttleRAF(fn) {
      let ticking = false;
      return function(...args) {
        if (!ticking) {
          requestAnimationFrame(() => {
            fn.apply(this, args);
            ticking = false;
          });
          ticking = true;
        }
      };
    }

总结

  • 防抖:高频事件结束后触发,避免重复执行(如输入验证)
  • 节流:高频事件按节奏触发,保障最低执行频率(如滚动计算)
  • 生产建议:直接使用 Lodash 的 _.debounce_.throttle(已处理大量边界情况)