图解 debounce 与 throttle 的区别

转载 2016年05月31日 16:56:32

在实现一些需要被频繁调用的函数时,我们通常都会使用 debounce 或 throttle方法。在我的印象中,它们的作用就是减少函数被调用的次数,但具体有什么区别,却真的不能说清楚。

直到最近看了一篇精彩的 博文 ,用可视化的方法展示了两者的区别,很有启发性,值得参考。

注意到上图,第一行 Mousemove Events 展示了 mousemove 事件触发的频率。第二行和第三行是分别使用 underscore 与 jQuery 的 debounce 方法后事件的触发频率。第四、五行则是增加了一个 delay 参数后的触发频率。与之对比的是最后三行,使用的是 throttle 方法。

首先我们的直观感觉是使用 debounce 方法相比于 throttle 方法事件触发的频率更低,但实际上不能这么理解。要解释上图的结果,首先需要了解 debounce 和 throttle 的原理。

当我们阅读 lodash 的代码时会发现,throttle 方法不过是 debounce 方法的一个修饰。也就是说,_.throttle 和 _.debounce 最终都会都会调用 debounce 方法。那么 debounce 究竟是如何工作的呢?

首先看 _.debounce 的 API:

_.debounce(func, delay, options);  

func 是需要被调用的目标函数,delay 是时间限制,options 是一系列的配置,为了简化问题,这里不多提。

当调用 _.debounce 后,会返回一个函数,这个函数在被调用时会生成一个 setTimeout(delayed, delay)。其中 delayed 又是一个内部方法,在 delayed 被调用时进行如下检测:当前时间 - 上次func被调用事件 是否 小于 0 或 大于 delay ?如果是则执行一次 func,记录并返回执行结果,同时更新上次被调用时间;如果不是则调用 setTimeout 进行下一次的判断。

因此,当你像下面这样绑定事件,

$(window).on('mousemove', _.debounce(moveHandler, 500));

并频繁移动鼠标时,你会发现 moveHandler 压根没有被调用过!直到你停下来后,moveHandler 才会被调用一次。

至于 _.throttle 方法,只不过是多给 debounce 传了一个 maxWait 选项,这个选项的意思是至少保证在每 maxWait 时间让 func 被调用一次。

说到这儿,你应该就明白了为什么会出现上图那样的调用情况。如果你频繁的移动鼠标,throttle 会保证在每 maxWait 时间调用 func 一次,而 debounce 如果没有明确设置 maxWait,是一直不会调用 func 直到你停止移动鼠标后才会调用一次。

因此,可以笼统的说 _.throttle 就是设置了 leading=true, trailing=true 及 maxWait 的 _.debounce。

那什么时候该用 debounce 什么时候该用 throttle 呢?

下面我列举了一些场景:

  • input 中输入文字自动发送 ajax 请求进行自动补全: debounce
  • resize window 重新计算样式或布局:debounce
  • scroll 时更新样式,如随动效果:throttle

最重要的还是理解两者对调用时间及次数上的处理,根据业务逻辑选择最合适的优化方案!

Debounce 和 Throttle 的原理及实现

在处理诸如 resize、scroll、mousemove 和 keydown/keyup/keypress 等事件的时候,通常我们不希望这些事件太过频繁地触发,尤其是监听程序中涉及到大量的计算或者有...
  • redtopic
  • redtopic
  • 2017年04月06日 16:49
  • 2880

_.debounce 应用

1,定义。  如果用手指一直按住一个弹簧,它将不会弹起直到你松手为止。 也就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。(空闲时间大于,设定的时...
  • LABa2
  • LABa2
  • 2017年04月26日 20:56
  • 2014

RxJava过滤操作符 debounce

debounce操作符是对源Observable间隔期产生的结果进行过滤,如果在这个规定的间隔期内没有别的结果产生,则将这个结果提交给订阅者,否则忽略该结果,原理有点像光学防抖. .debounce...
  • axuanqq
  • axuanqq
  • 2016年02月29日 10:06
  • 1666

debounce函数

当在扩展一个Angular应用的时候,巨大的数据集导致$digest()循环运行缓慢,处理这个$digest()循环延迟问题的方案是使用debounce函数。提示:debounce函数是指,只要它一直...
  • u013291076
  • u013291076
  • 2015年01月09日 17:31
  • 892

debounce与throttle实现与原理

前言前端时间在面试中,面试官让我写一个关于input输入框,并且实时搜索的问题,我就当然用keyup事件来写,写完面试官还是挺满意的。又问我一个问题,如何减少每次输入频繁请求的性能开销。这个我就犯难了...
  • blueblueskyhua
  • blueblueskyhua
  • 2017年07月22日 20:27
  • 546

lodash 中文学习拾零之 Chain篇

作者:Soaring_Tiger 转载请注明出处 前情提要: lodash中文学习拾零之Array篇2、Chain 可以说是 lodash 中最为重要的部件,想要用lodash进行复杂的多步操作都离不...
  • Soaring_Tiger
  • Soaring_Tiger
  • 2015年09月11日 16:33
  • 4090

debounce与throttle区别

在2011年,Twitter网站曾爆出一个问题:在主页往下滚动时,页面会变得缓慢以致没有响应。John Resig发表了一篇文章《 a blog post about the problem》指出直接...
  • ligang2585116
  • ligang2585116
  • 2017年07月12日 08:13
  • 1028

JavaScript 节流函数 Throttle 详解

在浏览器 DOM 事件里面,有一些事件会随着用户的操作不间断触发。比如:重新调整浏览器窗口大小(resize),浏览器页面滚动(scroll),鼠标移动(mousemove)。也就是说用户在触发这些浏...
  • u013510614
  • u013510614
  • 2016年07月15日 20:23
  • 6291

函数节流(throttle)与函数去抖(debounce)

以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃。   1. window对象的resize、scroll事件   2. 拖拽时的mou...
  • baidu_31333625
  • baidu_31333625
  • 2016年10月05日 17:09
  • 1106

debounce与throttle实现与原理

前言前端时间在面试中,面试官让我写一个关于input输入框,并且实时搜索的问题,我就当然用keyup事件来写,写完面试官还是挺满意的。又问我一个问题,如何减少每次输入频繁请求的性能开销。这个我就犯难了...
  • blueblueskyhua
  • blueblueskyhua
  • 2017年07月22日 20:27
  • 546
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:图解 debounce 与 throttle 的区别
举报原因:
原因补充:

(最多只允许输入30个字)