Underscore.js 中 _.throttle 和 _.debounce 的差异

 
两个方法都是用来控制事件的频率的,在mousemove,resize等这种高频率触发事件中,控制其响应频率可以明显提高程序的流畅性,减少资源的占用。

通过分析其源代码:

_.throttle方法源码

/**

 * 频率控制 返回函数连续调用时,func 执行频率限定为 次 / wait

 *

 * @param  {function}   func      传入函数

 * @param  {number}     wait      表示时间窗口的间隔

 * @param  {object}     options   如果想忽略开始边界上的调用,传入{leading: false}。

 *                                如果想忽略结尾边界上的调用,传入{trailing: false}

 * @return {function}             返回客户调用函数  

 */

_.throttle = function(func, wait, options) {

  var context, args, result;

  var timeout = null;

  // 上次执行时间点

  var previous = 0;

  if (!options) options = {};

  // 延迟执行函数

  var later = function() {

    // 若设定了开始边界不执行选项,上次执行时间始终为0

    previous = options.leading === false ? 0 : _.now();

    timeout = null;

    result = func.apply(context, args);

    if (!timeout) context = args = null;

  };

  return function() {

    var now = _.now();

    // 首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。

    if (!previous && options.leading === false) previous = now;

    // 延迟执行时间间隔

    var remaining = wait - (now - previous);

    context = this;

    args = arguments;

    // 延迟时间间隔remaining小于等于0,表示上次执行至此所间隔时间已经超过一个时间窗口

    // remaining大于时间窗口wait,表示客户端系统时间被调整过

    if (remaining <= 0 || remaining > wait) {

      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;

  };

};

 

_.debounce方法源码

/**

 * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行

 *

 * @param  {function} func        传入函数

 * @param  {number}   wait        表示时间窗口的间隔

 * @param  {boolean}  immediate   设置为ture时,调用触发于开始边界而不是结束边界

 * @return {function}             返回客户调用函数

 */

_.debounce = function(func, wait, immediate) {

  var timeout, args, context, timestamp, result;

 

  var later = function() {

    // 据上一次触发时间间隔

    var last = _.now() - timestamp;

 

    // 上次被包装函数被调用时间间隔last小于设定时间间隔wait

    if (last < wait && last > 0) {

      timeout = setTimeout(later, wait - last);

    } else {

      timeout = null;

      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用

      if (!immediate) {

        result = func.apply(context, args);

        if (!timeout) context = args = null;

      }

    }

  };

 

  return function() {

    context = this;

    args = arguments;

    timestamp = _.now();

    var callNow = immediate && !timeout;

    // 如果延时不存在,重新设定延时

    if (!timeout) timeout = setTimeout(later, wait);

    if (callNow) {

      result = func.apply(context, args);

      context = args = null;

    }

 

    return result;

  };

};

_.throttle像一个节流阀,在预设时间内,不管事件触发多少次,只执行一次,而_.debounce则像电梯,只有当两次事件触发的间隔大于预设时间,才会触发事件。如果电梯里有人进来,开始等待。如果又人进来,重新计时等待,直到超过预设时间,开始执行

你可能感兴趣的:(underscore)