防抖 - 节流

78 阅读1分钟

防抖

// 接收一个需要做防抖的函数 需要防抖多久(不传默认666ms)
function debounce(fn, delay = 666, immediate = false, callBack) {
  // 存储计时器 标记是否立即执行
  let timer,
    isInvoke = true;

  // 真正返回触发的函数
  function _debounce(...args) {
    // 判断是否立即执行
    if (immediate && isInvoke) {
      const result = fn.apply(this, args);
      // 每次立即执行完成后让立即执行状态变成不再立即执行
      isInvoke = false;
      // 利用回调函数将返回值传递出去
      if (callBack) callBack(result);
    } else {
      // 每次触发之前判断一下之前有没有计时器(有则代表目前属于防抖时间)[清除掉上次的函数准备执行时间]
      if (timer) clearTimeout(timer);

      timer = setTimeout(() => {
        // 满足了调用条件调用并传入this和event事件参数
        const result = fn.apply(this, args);
        // 每次延迟执行后将立即执行状态调回
        if (!isInvoke) isInvoke = true;

        if (callBack) callBack(result);
      }, delay);
    }
  }

  // 取消
  _debounce.cancel = function () {
    if (timer) clearTimeout(timer);
  };

  return _debounce;
}

// 调用
<input type="text" />

const inpt = document.querySelector('input');
// 这里绑定的是debounce返回值函数
inpt.addEventListener(
  'input',
  debounce(getSource, 1000, true, res => {
    console.log(res);
  })
);

function getSource(e) {
  console.log('发了请求', this, e);

  return '请求返回值';
}

节流

function throttle(fn, delay = 666, immediate = false, callBack) {
  let timer = null, isInvoke = true;

  function _throttle(...args) {
    if (immediate && isInvoke) {
      const result = fn.apply(this, args);

      isInvoke = false;

      if (callBack) callBack(result)
    } else {
      if (timer) return;

      timer = setTimeout(() => {
        const result = fn.apply(this, args);

        if (callBack) callBack(result)

        timer = null;
      }, delay);
    }
  }

  _throttle.cancel = function () {
    if (timer) clearTimeout(timer)
  }

  return _throttle;
}

// 调用
<input type="text" />

const inpt = document.querySelector('input');

inpt.addEventListener(
  'input',
  throttle(getSource, 666, true, res => {
    console.log(res);
  })
);

function getSource(e) {
  console.log('发了请求', this, e);

  return '请求返回值';
}
// 取消
console.log(throttle().cancel);