Skip to content

快速搞定防抖节流函数

Published: at 00:13Suggest Changes

防抖节流函数是什么

防抖函数(debounce):n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

节流函数(throttle):n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

为什么要防抖节流函数

本质上是优化高频率执行代码的一种手段,对浪费资源的事件采取限制调用次数的限制

常见应用场景

防抖在连续的事件,只需触发一次回调的场景有:

节流在间隔一段时间执行一次回调的场景有:

代码实现

防抖

function debounce(func, wait) {
  let timeout;

  return function () {
    let context = this; // 保存this指向
    let args = arguments; // 拿到event对象

    clearTimeout(timeout);
    timeout = setTimeout(function () {
      func.apply(context, args);
    }, wait);
  };
}

防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:

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

  return function () {
    let context = this;
    let args = arguments;

    if (timeout) clearTimeout(timeout); // timeout 不为null
    if (immediate) {
      let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
      timeout = setTimeout(function () {
        timeout = null;
      }, wait);
      if (callNow) {
        func.apply(context, args);
      }
    } else {
      timeout = setTimeout(function () {
        func.apply(context, args);
      }, wait);
    }
  };
}

节流

利用定时器实现节流函数:

function throttled(fn, delay = 500) {
  let timer = null;
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(this, args);
        timer = null;
      }, delay);
    }
  };
}

利用时间戳实现节流函数,时间会立即执行,停止触发后没办法再次执行:

function throttled(fn, delay = 500) {
  let oldTime = Date.now();
  return function (...args) {
    let newTime = Date.now();
    if (newTime - oldTime >= delay) {
      fn.apply(null, args);
      oldTime = Date.now();
    }
  };
}

将时间戳写法的特性与定时器写法的特性相结合,更精确:

function throttled(fn, delay) {
  let timer = null;
  let startTime = Date.now();
  return function () {
    let curTime = Date.now(); // 当前时间
    let remaining = delay - (curTime - startTime); // 从上一次到现在,还剩下多少多余时间
    let context = this;
    let args = arguments;
    clearTimeout(timer);
    if (remaining <= 0) {
      fn.apply(context, args);
      startTime = Date.now();
    } else {
      timer = setTimeout(fn, remaining);
    }
  };
}

总结

相同点

不同点

函数防抖函数节流
在一段连续操作结束后,处理回调,利用 clearTimeoutsetTimeout 实现在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
希望一定时间连续触发的事件只在最后执行一次希望一定时间连续触发的事件一段时间内只执行一次

参考文章

  1. 面试官:什么是防抖和节流?有什么区别?如何实现?

  2. 彻底弄懂函数防抖和函数节流 - SegmentFault 思否


Previous Post
详述SSH的原理及其应用
Next Post
Rust开发环境搭建