Vue防抖节流实现和clearTimeout(timeout) timeout=???、以及定时器有什么变化?

1,109 阅读3分钟

小知识,大挑战!本文正在参与“  程序员必备小知识  ”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

前言

  • 防抖节流我相信大家都不陌生,简单理解,可有效的规避很多重复性(误)操作。
  • 防抖:在规定时间内,操作时长间接性小于规定时间,只执行第一次或者最后一次;如:500ms执行一次,间接时间为100ms,一共操作时长2000ms,则会执行1次。
  • 节流:规定时间内执行一次,操作时长大于规定时间,则开启下一个执行;如:500ms执行一次,一共操作时长2000ms,则会执行4次。

问题所在

问题:clearTimeout(timeout)后,timeout=???、以及定时器有什么变化?

先简单过一下 下图的代码,平淡无奇哈,但是关键在于这句 timeout && clearTimeout(timeout),试想经过clearTimeout(timeout)后,timeout=???,等于null吗?可以看到清除定时器后timeout的值并非null,而且还不变,这是不是有点匪夷所思啊?

  • 接下来我们分析一下,我们开启一个定时器,并且把这个定时器记录赋给一个变量,这时候定时器在内存中,可以通过该变量对应id去查找到,经过clearTimeout(timeout)后,只是对内存中的定时器进行清除,仅此而已,并未对变量进行修改操作;
  • 如果我们直接进行timeout=null,而没有clearTimeout(timeout),那么定时器是没有清除的,只是把timeout指向变了,并没有清除掉定时器,此时定时器在内存中虽然没有变量指向它,但它仍存在内存中,待wait时间一到,就执行callback函数。

防抖函数实现

/**
 * 防抖函数:多次触发事件,事件处理函数只执行一次,并且在触发操作后执行。
 * 原理:利用闭包原理,就是函数需要在刚完成时需要被使用,赋值给一个变量,由这个变量去使用。
 * @param {*} callback 回调函数
 * @param {*} wait 延迟时间,默认500ms
 * @param {*} immediate 是否立即执行,默认是
 */
export const debounce = (callback, wait = 500, immediate = true) => {
  let timeout = null;
  let debounced = function() {
    let self = this;
    timeout && clearTimeout(timeout);
    if (immediate) {
      let callNow = !timeout;
      if (callNow) callback.apply(self, arguments);
      timeout = setTimeout(() => {
        timeout = null;
      }, wait);
    } else {
      timeout = setTimeout(() => {
        callback.apply(self, arguments);
      }, wait);
    }
  };
  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  };
  return debounced;
};

节流函数实现

顺便附上节流函数

/**
 * 节流函数:触发操作后,在间隔连续时间内只执行一次,过了规定间隔时间后,才进行下一次调用
 * 原理:对函数进行间隔操作,在规定间隔时间内,如有重复操作,则清除掉本次操作
 * @param {*} callback
 * @param {*} wait 间隔时间,默认500ms
 * @param {*} options = { leading: false, // 禁用第一次执行 trailing: false // 禁用停止触发的回调 }
 * @returns
 */
export const throttle = (callback, wait = 500, options = {}) => {
  let time, context, args;
  let previous = 0;
  let later = function() {
    previous = options.leading === false ? 0 : new Date().getTime();
    time = null;
    callback.apply(context, args);
    if (!time) context = args = null;
  };
  let throttled = function() {
    let now = new Date().getTime();
    if (!previous && options.leading === false) previous = now;
    let remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
      if (time) {
        clearTimeout(time);
        time = null;
      }
      previous = now;
      callback.apply(context, args);
      if (!time) context = args = null;
    } else if (!time && options.trailing !== false) {
      time = setTimeout(later, remaining);
    }
  };
  throttled.cancel = function() {
    clearTimeout(time);
    time = null;
    previous = 0;
  };
  return throttled;
};

期待

欢迎留言和点赞收藏哦~~~