面试题---区别函数节流与防抖

1. 事件高频触发处理的问题

  1. 如果更新界面 => 界面更新卡顿
  2. 如果发送ajax请求 => 发送了很多没必要的请求

2. 解决办法

  1. 函数节流
  2. 函数防抖

3. 区别:

  1. 节流函数 (throttle)

    • 接受两个参数:需要节流的回调函数callback和延迟时间delay
    • 通过保存上一次处理事件的时间start,确保在连续触发事件时,只有当当前时间与上一次处理事件的时间差大于设定的延迟时间delay时,才会执行回调函数callback
  2. 防抖函数 (debounce)

    • 同样接受两个参数:需要防抖的回调函数callback和延迟时间delay
    • 每当事件触发时,如果存在尚未执行的定时器,则清除它,然后重新启动一个延迟时间为delay的新定时器。
    • 只有当事件触发后,在指定延迟时间内没有再次触发事件时,才会执行回调函数callback

简单来讲:当事件高频发生很多次时, 防抖只执行最后一次, 而节流执行少量几次

4. 应用场景

节流: 窗口调整(resize)/ 页面滚动(scroll)/ OM元素的拖拽功能实现(mousemove)

防抖: 输入搜索联想功能

5.自定义函数节流与防抖

// 节流函数 (throttle)
function throttle(callback, delay) {
    let start = 0; // 用于保存处理事件的时间,初始值为0,保证第一次会执行

    // 返回事件监听函数 => 每次事件发生都会执行此返回的函数
    return function(event) {
        console.log('-- throttle --');

        // 发生事件的当前时间
        const current = Date.now();

        // 与上一次处理事件的时间差大于delay的时间
        if (current - start > delay) {
            // 执行处理事件的函数
            callback.call(event.target, event);

            // 保证当前时间为最新的处理事件时间
            start = current;
        }
    }
}

// 防抖函数 (debounce)
function debounce(callback, delay) {
    // 返回事件监听函数 => 每次事件发生都会执行此返回的函数
    return function(event) {
        console.log('-- debounce --');

        // 如果还有未执行的定时器,清除它
        if (callback.timeoutId) {
            clearTimeout(callback.timeoutId);
        }

        // 启动延迟delay的定时器,并保存定时器id
        callback.timeoutId = setTimeout(() => {
            // 执行处理事件的函数
            callback.call(event.target, event);

            // 删除保存的定时器id
            callback.timeoutId = null;
        }, delay);
    }
}

要使用这两个工具函数,可以这样调用它们:

// 假设有一个需要节流的scroll事件处理器
const handleScrollThrottled = throttle(handleScroll, 200);

window.addEventListener('scroll', handleScrollThrottled);

// 假设有一个需要防抖的resize事件处理器
const handleResizeDebounced = debounce(handleResize, 500);

window.addEventListener('resize', handleResizeDebounced);