1. 基本概念

1.1 防抖(Debounce)

  • 定义:在一定时间内,多次触发同一事件,只执行最后一次
  • 核心思想:等待用户停止操作一段时间后才执行
  • 适用场景:搜索框输入、窗口大小调整、表单提交等

1.2 节流(Throttle)

  • 定义:在一定时间内,多次触发同一事件,按照固定的时间间隔执行
  • 核心思想:按照固定的频率执行,不管触发多少次
  • 适用场景:滚动事件、按钮点击、游戏中的移动等

2. 核心区别对比

特性防抖(Debounce)节流(Throttle)
执行时机等待停止触发后执行按固定时间间隔执行
执行次数只执行最后一次按频率执行多次
响应性延迟响应立即响应,后续按频率
适用场景搜索、提交、调整大小滚动、点击、移动

3. 代码实现对比

3.1 防抖实现

function debounce(func, delay) {
    let timer = null;
    
    return function(...args) {
        // 清除之前的定时器
        if (timer) {
            clearTimeout(timer);
        }
        
        // 设置新的定时器
        timer = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}
 
// 使用示例
const handleSearch = debounce((searchTerm) => {
    console.log('搜索:', searchTerm);
    // 发起API请求
}, 500);
 
// 用户输入时
input.addEventListener('input', (e) => {
    handleSearch(e.target.value);
});

3.2 节流实现

function throttle(func, delay) {
    let lastTime = 0;
    
    return function(...args) {
        const now = Date.now();
        
        // 如果距离上次执行的时间超过delay,则执行
        if (now - lastTime >= delay) {
            func.apply(this, args);
            lastTime = now;
        }
    };
}
 
// 使用示例
const handleScroll = throttle(() => {
    console.log('滚动事件触发');
    // 处理滚动逻辑
}, 200);
 
// 滚动时
window.addEventListener('scroll', handleScroll);

这个实现可能会错过最后一次执行,只是简单演示。

以下是更完善的版本。

function throttle(func, delay) {
    let lastTime = 0;
    let timer = null;
    
    return function(...args) {
        const now = Date.now();
        
        if (now - lastTime >= delay) {
            // 立即执行
            func.apply(this, args);
            lastTime = now;
        } else {
            // 在延迟期间,清除之前的定时器,设置新的定时器
            if (timer) {
                clearTimeout(timer);
            }
            
            // 确保在delay时间后执行最后一次
            timer = setTimeout(() => {
                func.apply(this, args);
                lastTime = Date.now();
            }, delay - (now - lastTime));
        }
    };
}

5. 高级实现版本

5.1 带立即执行选项的防抖

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

7. 选择建议

7.1 何时使用防抖

  • 用户输入搜索时
  • 窗口大小调整时
  • 表单提交防重复时
  • 需要等待用户停止操作时

7.2 何时使用节流

  • 滚动事件处理时
  • 按钮快速点击时
  • 游戏中的移动控制时
  • 需要按固定频率执行时