自己实现简单的函数防抖(debounce)和函数节流(throttle)

287 阅读2分钟

前言

前端的交互中,有些操作需要持续触发,而且频率非常高。比如:resize, scroll, mousemove, input等事件。而为了性能和效率,我们不需要让事件触发太多次。这就诞生了函数的防抖和节流。

防抖(debounce)

防抖简单说就是在设定的时间内,虽然操作上持续触发,通过定时器约束,我们也只执行函数触发的最后一次。

防抖函数可以分为延迟执行版和立即执行版

延迟执行版

 /*
  fn: 需要防抖的函数
  wait: 延迟毫秒数
  return: 函数
  */
  // 延迟执行
  function debounce(fn, wait) {
    var timer; // 全局的定时器 id
    return function () {
      var that = this; // 将函数被调用时的 this 保存
      var args = arguments; // 保存函数的参数
      if (timer) {
        clearTimeout(timer); // 清除 wait 时间内频繁调用函数产生的定时器
      }
      timer = setTimeout(() => {
        fn.apply(that, args); // 将传递进来的 fn 使用 apply 调用,将 this 指向改为保存的 that,同时进行传参
      }, wait);
    };
  }

立即执行版

 // 立即执行
  function debounce(fn, wait) {
    var timer;
    return function () {
      var that = this;
      var args = arguments;
      if (timer) {
        clearTimeout(timer);
      }
      if (!timer) fn.apply(that, args); // 首次进入, timer 为空,执行 fn 函数
      timer = setTimeout(() => {
        timer = null; // wait 毫秒后设置 timer 为空
      }, wait);
    };
  }

防抖应用场景

  • reseize 事件
  • 按钮 click 控制

节流(throttle)

节流就是按照给定的时间有规律的执行函数,可以通过时间戳和定时器实现。

节流函数可以分为定时器版和时间戳版

定时器版

 // 定时器版
  function throttle(fn, wait) {
    let timer;
    return function () {
      const that = this;
      const args = arguments;
      if (!timer) {
        timer = setTimeout(() => {
          fn.apply(that, args);
          timer = null;
        }, wait);
      }
    };
  }

时间戳版

 // 时间戳版
  function throttle(fn, wait) {
    let previous = 0;
    return function () {
      const that = this;
      const args = arguments;
      let now = Date.now();
      if (now - previous > wait) {
        fn.apply(that, args);
        previous = now;
      }
    };
  }

节流应用场景

  • 元素拖动
  • 搜索联想
  • 移动端上滑加载时判断距离底部的位置