美文网首页程序员技能getWeb前端之路
记录一下throttle和debounce函数

记录一下throttle和debounce函数

作者: wpzero | 来源:发表于2016-03-24 15:19 被阅读1272次

    由于最近看到了简书上关于这个的文章,想到原来在coding上看过这方面的文章所以记录总结一下。

    throttle (_.throttle(func, wait, options)

    这个函数的作用就是防止多次频繁的调用,规定在wait左右只能执行一次,目的是限制执行频率。
    用法如下:

    var throttled = _.throttle(updatePosition, 100);
    $(window).scroll(throttled);
    

    这样在滚动的时候就可以控制一下发生的频率。
    underscore的源码如下:

      _.throttle = function(func, wait, options) {
        var timeout, context, args, result;
        var previous = 0;
        if (!options) options = {};
    
        var later = function() {
          // 如果options.leading === false在这里重新设置 previous
          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每次都是最新的
          args = arguments;
          // 距离上次的时间已经大约wait,直接运行
          if (remaining <= 0 || remaining > wait) {
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
    
          // 这个是options.leading === false的时候做第一次调用
          // 或者wait之内再调用的时候
          } 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;
      };
    

    原理其实就是设置一个timer来控制发生的频率,用高阶函数来实现一个闭包,每次调用args都被赋予最新的值,最后调用fun的时候肯定是最新的args。保证一个wait左右只执行一个fn。
    然后我们来看看的他的亲兄弟debounce,看似很相似,其实应用场景是不太一样的。
    它的作用是拖延执行fun wait时间,wait内又调用fun那么再拖延wait时间,最后没有wait内调用那么执行,目的多次频繁的调用合并为一次执行,不需要中间的过程。
    应用场景如 form 的提交,防止两次频繁的点击。或者,markdown编辑同时渲染显示。

    var lazyLayout = _.debounce(calculateLayout, 300);
    $(window).resize(lazyLayout);
    

    这个应用只需要最后的size就好,不需要中间的多余计算。
    源码如下:

      _.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) {
          var callNow = immediate && !timeout;
          if (timeout) clearTimeout(timeout);
          if (callNow) {
            timeout = setTimeout(later, wait);
            result = func.apply(this, args);
          } else if (!immediate) {
            timeout = _.delay(later, wait, this, args);
          }
    
          return result;
        });
    
        debounced.cancel = function() {
          clearTimeout(timeout);
          timeout = null;
        };
    
        return debounced;
      };
    

    每次调用都清掉先前的timeout,推移一个timeout。
    如果immediate为true的话,立刻调用,然后wait内不可以再次调用,
    可以用于form提交。

    相关文章

      网友评论

        本文标题:记录一下throttle和debounce函数

        本文链接:https://www.haomeiwen.com/subject/kxerlttx.html