该篇为翻译文章,原文地址为:The Difference Between Throttling and Debouncing – CSS Tricks

我之前被”节流”和”去抖”搞得很糊涂,后来有人帮我解决了这个问题。所以我把它写在这里也给大家解释一下。它们两个都是用来解决DOM事件的回调被不停调用而引起的性能问题的。但它们是有一定区别的。

节流

“节流”是限制一个一直在执行的函数的最大执行次数。比如让一个本来要一直执行的函数以最多100毫秒执行一次的频率来执行。

比如现在你遇到一个很奇怪的情况,一个函数不得不在10秒内执行1000次,但是实际上你是不需要它执行这么多次的。如果你把它限制在100毫秒执行一次,那么这个函数最终最多只会执行100次。

(10s * 1,000) = 10,000ms
10,000ms / 100ms 的节流 = 100 次的最大执行数

去抖

“去抖”则是等一段时间之后再去调用函数(并且函数此时没有被调用)。比如,在过了100毫秒后调用一个函数,并且该函数此时没有被调用。

在某些情况,一个函数可能会在不经意之间被调用1000次,这1000次的函数执行可能会花费3秒,3秒过后函数停止调用。如果你做一个100毫秒的去抖操作,函数将只会执行一次,在3.1秒的时候,也就是在你”不经意之间”结束的时候。

什么时候要”节流”和”去抖”

“节流”和”去抖”最重要的一个应用场景就是在某些DOM事件绑定上面,像是滚动和缩放窗口事件。比如一个元素绑定了滚动事件,当元素滚动了5000像素,你可能会发现你的事件函数执行了100多次。如果你的事件函数里有大量的代码(比如有一些大量的计算或者大量的DOM操作),那么则会产生一些性能上的问题。而这个时候如果你想在保证用户体验的同时做一些性能上的提升,那么就要看看”节流”或”去抖”的作用了。

一些常见的应用场景:

  • 缩放浏览器窗口结束时
  • 当输入停止时再发送Ajax请求
  • 以最多50毫秒为时间单位来获取滚动的位置或者执行回调
  • 在做拖拽操作的时候保证良好的性能

如何使用”节流”和”去抖”

这两个功能在UnderscoreLodash中都有集成。即使你的项目中不使用这两个库,你也可以把这些功能单独提取出来。

在滚动事件当中使用”节流”:

$("body").on('scroll', _.throttle(function() {
  // Do expensive things
}, 100));

在缩放事件当中使用”去抖”:

$(window).on('resize', _.debounce(function() {
  // Do expensive things
}, 100));

还有一个相对来说比较高级的做法,就是使用requestAnimationFrame,使用了requestAnimationFrame后,浏览器会在适当的时候执行函数。具体请看Paul Lewis的这篇文章.

最后通过下面这个Demo来体验一下它们之间的差别:

See the Pen The Difference Between Throttling, Debouncing, and Neither by Chris Coyier (@chriscoyier) on CodePen.