手撕防抖和节流函数

223 阅读2分钟

防抖

防抖函数的概念:

  1. 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间
  2. 当事件频繁的被触发时,函数的触发会被频繁的推迟
  3. 只有等待了一段时间后,没有事件继续触发,函数才会执行
/* 
防抖函数
实现功能:
1.绑定正确的this
2.是否立即触发第一次事件
3.取消最后一次的事件
4.使用promise来返回执行的结果
*/
function debounce(fn, delay, immediate = false) {
  let timer = null;
  let first = true; //标志是否是第一次
  function _debounce(...args) {
    return new Promise((resolve, reject) => {
      if (timer) clearTimeout(timer);

      //判断是否立即执行
      if (immediate && first) {
        const res = fn.apply(this, args);
        resolve(res);
        first = false;
      } else {
        timer = setTimeout(() => {
          const res = fn.apply(this, args);
          resolve(res);
          //执行了timer,说明本次防抖结束了,重置first=true
          first = true;
          timer = null;
        }, delay);
      }
    });
  }

  //取消最后一次的执行
  _debounce.cancel = function () {
    clearTimeout(timer);
    first = true;
    timer = null;
    console.log("取消成功");
  };

  return _debounce;
}

节流

节流的概念:

  1. 当事件触发时,会执行这个事件的响应函数
  2. 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数
  3. 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的
/* 
    节流函数
    实现的功能:
    1.绑定正确的this
    2.Promise返回函数的结果
    3.leading和trailing分别控制第一次和最后一次是否执行
    4.取消最后一次的事件
*/

function throttle(fn, interval, options = {leading: true, trailing: true}) {
  let timer = null;
  let lastTime = 0;
  //leading 第一次事件是否执行 ,trailing:最后一次事件是否执行
  let {leading, trailing} = options;
  function _throttle(...args) {
    return new Promise((resolve, reject) => {
      let curTime = new Date().getTime();
      //leading为false,第一次不执行 使lastTime = curTime 那么restTime>0,第一次事件就不会执行
      if (!leading && !lastTime) lastTime = curTime;
      //剩余时间
      let restTime = interval - (curTime - lastTime);

      if (restTime <= 0) {
        if (timer) {
          clearTimeout(timer);
          timer = null;
        }

        const res = fn.apply(this, args);
        resolve(res);
        lastTime = curTime;
        return;
      }
      //只有timer=null时,创建定时器,避免重复的创建定时器
      if (trailing && !timer) {
        timer = setTimeout(() => {
          const res = fn.apply(this, args);
          resolve(res);
          //如果leading=false ,那么第一次不执行,应该将lastTime重置为0
          lastTime = !leading ? 0 : new Date().getTime();
          timer = null;
        }, restTime);
      }
    });
  }
  _throttle.cancel = function () {
    console.log("取消成功");
    if (timer) clearTimeout(timer);
    timer = null;
    lastTime = 0;
  };
  return _throttle;
}

更多好文移步龙仔的个人博客(longzai1024.top/home ),谢谢关注!