throttle和debounce

  1. 意义解释
  2. 自己实现 throttle
  3. underscore 的实现 throttle
  4. 自己实现 debounce
  5. underscore 的实现 debounce

这两个都是处理密集调用的函数,看高级程序设计 614 页的时候,发现写的有问题,书里将 throttle 和 debounce 搞混了。于是重新整理了一下。

意义解释

throttle 这个是在高频调用时,保证多少毫秒内只会被执行一次,还是会不断地触发,但是限制了频率。

特别适合的场景:比如在 resize 触发的时候,页面会被不停地重绘,如果在 resize 里面还加上了 DOM 操作的话,对于浏览器的压力很大。设置了 throttle 之后,就可以设置成 50ms 触发一次重绘。

debounce 是在多少毫秒内不再被触发的时候,就会执行一次,如果不停的调用的话,他实际上最后其实只是执行一次。比如在线编辑的自动存储,比较适合这种处理的逻辑。

自己实现 throttle

自己根据特性简单的实现了一下

function throttle(fn, timeout, context) {
  //如果上次没调用过,直接调用
  if (!fn.lastExec) {
    fn.lastExec = Date.now();
    fn.call(context);
  } else {
    //如果调用过 --- 如果这次的调用时间超过了设置的设定好的timeout
    var remaining = Date.now() - fn.lastExec;
    if (remaining > timeout) {
      //新调用
      fn.lastExec = Date.now();
      fn.call(context);
    }
  }
}
var fn = function() {
  console.log(Date.now());
};
for (var i = 1; i <= 10; i++) {
  setTimeout(function() {
    throttle(fn, 2000);
  }, 1000 * i);
}
function debounce(fn, timeout, context) {
  //如果上次调用过还没执行,就清除掉,重设定时
  clearTimeout(fn.dId);
  fn.dId = setTimeout(function() {
    fn.call(context);
  }, timeout);
}

我写的 throttle 的函数的缺陷:

  • 我的节流会根据调用的频率产生误差,频率越小,我的误差会越大,因为我只是阻止了时间内的调用,并没有为了他再设置一个定时器
  • 我把数据都直接挂在了 fn 上,太 Low 了,应该用一个闭包,把数据存在内存中,并且外部也没有访问的可能

underscore 的实现 throttle

顺便去看下别人的模块是怎么写的

_.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;
    //如果剩余时间小于0,清空timeout,立即调用
    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并且不禁止最后一次调用,那就设置定时重新运行
      timeout = setTimeout(later, remaining);
    }
    return result;
  };
  throttled.cancel = function() {
    clearTimeout(timeout);
    previous = 0;
    timeout = context = args = null;
  };
  return throttled;
};
var fn = _.throttle(function() {
  console.log(Date.now());
}, 2000);
for (var i = 1; i < 10; i++) {
  setTimeout(fn, 1000 * i);
}

underscore 的实现解决了我的调用的误差问题,如果时间到了,直接执行;时间不到,就设置一个剩余时间的定时器来执行。很有意思的实现。

自己实现 debounce

function debounce(fn, timeout, context) {
  //如果上次调用过还没执行,就清除掉,重设定时
  clearTimeout(fn.dId);
  fn.dId = setTimeout(function() {
    fn.call(context);
  }, timeout);
}
var fn = function() {
  console.log(Date.now());
};
for (var i = 1; i <= 5; i++) {
  setTimeout(function() {
    debounce(fn, 2000, null);
  }, 1000 * i);
}

debounce 的实现比较简单,应该也不会错。除了没用闭包,有些 low 之外。

underscore 的实现 debounce

_.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;
};
  • 他的实现主要是加上了 immediate 的支持,就是在第一次调用的时候直接执行,并且在接下来的时间内不会再执行。用于防止那种不小心提交按钮点击了两次的情况是很管用的。
  • 而且他的实现都提供了 cancel 方法来清除定时,防止出问题,蛮好的。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 981909093@qq.com

文章标题:throttle和debounce

文章字数:1k

本文作者:泽鹿

发布时间:2019-08-28, 16:45:23

最后更新:2019-08-28, 16:45:23

原始链接:http://panyifei.github.io/2019/08/28/技术/前端技术/throttle和debounce/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏