Debounce and Throttle 的可视化解释

Debounce and Throttle 的可視化解釋

Debounce 和 Throttle是两个概念,我们可以在 JavaScript 中使用,以提高我们对执行功能的控制,在事件处理的时候特别有用。

比喻

这两种技术都回答同样的问题“一个功能可以随着时间被推移多久?”

  • Debounce:把它看成是“多个分组事件之一”。试想一下,你回家,再进入电梯,门正在关闭……,突然你的邻居出现在大厅,并试图跳上电梯。要有礼貌!并打开大门,他说:你等等,让我一起上。相同的情况下,可以与第三人再次发生,等等…这可能会延缓出发几分钟。
  • Throttle:把它看成是一个阀,它规定了执行的流程。我们可以判断函数可以在一定时间内被调用的最大次数。因此,再用电梯比喻..你有足够的礼貌,持续10秒等人,但一旦时间到了,你一定要走!

无 Debounce 或 Throttle 事件处理程序就像一次只能一个人用的电梯:没有那么高效。

我希望这个坏比喻对你有所帮助,但有时言语并不会对掌握这些概念有多大的帮助,所以我创建了一个演示去理解 Debounce 和 Throttle 概念,并把它们应用到mousemove事件。

function elevator_departure(name){
  alert(name + " was the last one. Nobody else? Let's go then");
};
var debounced_elevator_departure = $.debounce(200, false, elevator_departure);

debounced_elevator_departure('John');
debounced_elevator_departure('Mike');
debounced_elevator_departure('Peter');
// You will see *only* one message, "Peter was the last one. Nobody else? Let's go then";

我发现这3个人在JavaScript中都通过debounce和throttle执行了。我真的建议你先读一下 Ben Alman's 的文章,以便更好地理解 debounce 和 throttle. underscorelodash 有不同的实现方式,但参数都是一样的(除了 throttle没有 trailing).

演示

这里是视觉演示:

这是截图:

debounce-throttle

注意:

  • 这个的源代码演示在GitHub上托管
  • 如果你看到动画在浏览器中并不流畅,请在一个单独的页面打开演示,或者尝试在Chrome中。
  • 我通过在鼠标区域 tapping来去在Android环境下演示它
  • 每个单元代表约30毫秒,但JS是单线程的,所以浏览器是不是准确。这个演示并不是想成为一个最佳实践,只是为了更好地去理解概念。
  • 当你做了setTimeout,时间间隔可能不同,在每个浏览器在4ms和15ms的之间(尼古拉斯Zakas的文章),甚至是setTimeout(fn,0)至少需要4毫秒。在另一方面,时间为1毫秒为最小单位的。
  • mousemove第一行中的事件也有做节流(80毫秒)。这对理解演示有所帮助。
  • 要获得 trailing选项$.throttle,你需要传递false
  • 不要忘了,这一切都是builder,他们返回一个函数,所以你只需要执行一次。

应用场景

debounce 案例

用它减少执行频繁的事件。例子:

  • 当将要处理的textarea的快速打字:你不想执行处理函数,直到用户停止输入再来处理文本。
  • 当数据保存到通过AJAX服务器:你不想每秒调用非常缓慢的邮件服务器

throttle 案例

debounce 一样,但如果想每隔一段时间必须执行事件,可以使用它:

  • 假设用户不停地快速输入30秒,可能你会想每5秒执行一次函数;
  • 一些对性能有影响的事件但又必须处理:scroll, mouseweel, mousemove。一个简单的鼠标滚轮运动可以在一秒钟内触发几十个事件。

本文翻译自 Debounce and Throttle: a visual explanation

========= update on 11-21 =========

example

debounce

var validation = _.debounce(function () {
  ... // 校验输入,逻辑可能还会有点复杂
}, 250)
jQuery('input').keyup(validation) // 输入完成或停顿250ms后才去执行校验,如果不停输入10s,则10s内都不会触发
/**
 *  debounce第三个参数为可选参数,
 *  leading为true时,则在事件开始时首先执行一次, 默认值为 false;
 *  trailing为true时,则在结束时触发, 默认值为 true;
 *  maxWait设置每隔多长时间必须触发;
 */
function foo () { ... }
jQuery('input').on('keyup', _.debounce(foo, 300, {
  'leading': true, // 注意: 执行的前提是定时器为undefined
  'trailing': false,
  'maxWait': 1000
}));

// debounce还可以被取消
jQuery('button').on('click', function() {
  validation.cancel();
});

throttle

function mousemove () {
  ...
}
jQuery('#div').on('mousemove', _.throttle(mousemove, 100)) // 每100ms必须触发一次

// mousemove会在定时器开始时触发, 但5分钟内不会有第二次
jQuery('#div').on('mousemove', _.throttle(mousemove, 300000, {
  'leading': true, // 定时器前沿触发,默认值为true
  'trailing': false // 定时器后沿触发,默认值为true
}));
// throttle 同样可以被取消
jQuery(window).on('popstate', throttled.cancel);
0%