yliu

时来天地皆同力,运去英雄不自由

函数节流


本来打算从零写一个,不过意外看到一篇好文,下面就根据他的思路来实现一个节流,JavaScript专题之跟着 underscore 学节流

前言

节流有两种实现,第一种使用定时器,另外一种则是根据时间戳,判断两次执行的时间间隔,下面简单些一下这两种的实现。

  • 定时器
function throttle(fn, time) {
  let timing = null;
  return function(...rest) {
    if(!timing) {
      timing = setTimeout(() => {
        timing = null;
        fn.apply(this, rest);
      }, time);
    }
  };
};
  • 时间戳
function throttle (fn, time) {
  let times = 0;
  return function (...rest) {
    const s = time - (new Date().getTime() - times)
    if (s <= 0) {
      times = new Date().getTime();
      fn.apply(this, rest);
    }
  };
};

下面就是将两者结合起来

节流

// 节流
// initial初始立即执行,front最后执行一次
function throttle (fn, time, { initial = true, front = false } = {}) {
  // 上一次执行时间
  let times = 0;
  // 定时器
  let timing = null;
  function next (...args) {
    // 判断条件,如果不是初始执行,改用定时器方法执行
    if (!initial && !times) {
      times = new Date().getTime();
    }
    const now = time - (new Date().getTime() - times);
    // now > time是判断更改系统时间的边界问题,now正常情况下,肯定小于time
    if (now <= 0 || now > time) {
      if (!timing) {
        clearTimeout(timing);
        timing = null;
      }
      times = new Date().getTime();
      fn.apply(this, args);
      // 清理一下内存
      if (!timing) {
        args = null;
      }
    } else if (!timing && front) {
      timing = setTimeout(() => {
        timing = null;
        times = initial ? 0 : new Date().getTime();
        fn.apply(this, args);
        if (!timing) {
          args = null;
        }
      }, time);
    }
  }
  // 取消
  next.cancel = function () {
    clearTimeout(timing);
    timing = null;
    // 为0即可,上面有初始判断条件
    times = 0;
  };
  return next;
};

注意

上面有两个参数,但是不能同时设置为false