如何理解防抖debounce和节流throttle

本人通过阅读网络上防抖和节流多篇相关的文章,并借鉴相关案例进行说明。

防抖

防抖就像人眨眼睛一样,不可能不停的眨,每隔一定时间眨一下,防止眼睛干涩,如果不停眨眼,别人以为你眼睛有毛病了。
再举一个例子,比如两个人对话,A不停的balabala(持续触发),如果A说话的时候有停顿,但是停顿的时间不够长,B就认为A还没说完,当A停顿时间超过足够长(一定间隔)就认为A说完了,然后B开始说(响应)。

节流

节流就像排队过安检,当人很多的时候(持续触发),安保会隔一段时间放一部分人进行安检(一定间隔)。例如下图这个feel:

区别

要想真正搞懂防抖和节流,必须弄懂二者之间的异同。
防抖只会在连续的事件周期结束时执行一次,而节流会在事件周期内按间隔时间有规律的执行多次。

相同之处:

  1. 都是某个行为持续触发;

不同之处:

防抖:

  1. 结束完触发;
  2. 无规律;
  3. 周期内触发一次;

节流

  1. 达到一定条件就触发;
  2. 有规律;
  3. 周期内触发多次;
  4. 可以稀释函数触发频率;

巨人的肩膀

先来看看underscore中如何实现防抖和节流

// Returns a function, that, as long as it continues to be invoked, will not
  // be triggered. The function will be called after it stops being called for
  // N milliseconds. If `immediate` is passed, trigger the function on the
  // leading edge, instead of the trailing.
  _.debounce = function(func, wait, immediate) {
    var timeout, result;

    var later = function(context, args) {
      timeout = null;
      if (args) result = func.apply(context, args);
    };

    var debounced = restArgs(function(args) {
      if (timeout) clearTimeout(timeout);
      if (immediate) {
        var callNow = !timeout;
        timeout = setTimeout(later, wait);
        if (callNow) result = func.apply(this, args);
      } else {
        timeout = _.delay(later, wait, this, args);
      }

      return result;
    });

    debounced.cancel = function() {
      clearTimeout(timeout);
      timeout = null;
    };

    return debounced;
  };
// Returns a function, that, when invoked, will only be triggered at most once
  // during a given window of time. Normally, the throttled function will run
  // as much as it can, without ever going more than once per `wait` duration;
  // but if you'd like to disable the execution on the leading edge, pass
  // `{leading: false}`. To disable execution on the trailing edge, ditto.
  _.throttle = function(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
      previous = options.leading === false ? 0 : _.now();
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null; //显示地释放内存,防止内存泄漏
    };

    var throttled = function() {
      var now = _.now();
      if (!previous && options.leading === false) previous = now;
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      if (remaining <= 0 || remaining > wait) {
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        timeout = setTimeout(later, remaining);
      }
      return result;
    };

    throttled.cancel = function() {
      clearTimeout(timeout);
      previous = 0;
      timeout = context = args = null;
    };

    return throttled;
  };

大道至简

为了更好的理解,我找了一个精简版的防抖和节流

function debounce (fn, delay) {
    let timer   = null;

    return function () {
    let args = arguments;
    let context = this;

        if (timer) {
            clearTimeout(timer);

            timer = setTimeout(function () {
                fn.apply(context, args);
            }, delay);
        } else {
            timer = setTimeout(function () {
                fn.apply(context, args);
            }, delay);
        }
    }
}
function throttle (fn, delay) {
   let  timer    = null,
        remaining   = 0,
        previous = new Date();

    return function () {
        let now = new Date(),
        remaining = now - previous,
        args = arguments,
        context = this;

        if (remaining >= delay) {
            if (timer) {
                clearTimeout(timer);
            }

            fn.apply(context, args);
            previous = now;
        } else {
            if (!timer) {
                timer = setTimeout(function () {
                    fn.apply(context, args);
                    previous = new Date();
                }, delay - remaining);
            }
        }
    };
}

彩蛋

贴一个理解起来非常棒的demo案例:http://demo.nimius.net/debounce_throttle/

相关文章

  1. https://www.jianshu.com/p/c8b86b09daf0
  2. https://www.zhangshengrong.com/p/KWa3jQ3w1o/
  3. https://www.cnblogs.com/nanchen/p/7922959.html

你可能感兴趣的:(JavaScript,前端)