问题引出
在处理诸如resize
,scroll
,mousemove
和 keydown
, keyup
,keypress
等事件的时候, 我们通常不希望这些事件太过频繁的触发。尤其是监听程序中涉及到大量的计算或者是非常耗资源的操作。
有多频繁呢? 我们以mousemove
为例,根据 DOM Level 3 的规定,。
A user agent MUST dispatch this event when a pointing device is moved while it is over an element. The frequency rate of events while the pointing device is moved is implementation-, device-, and platform-specific, but multiple consecutive
mousemove
events SHOULD be fired for sustained pointer-device movement, rather than a single event for each instance of mouse movement. Implementations are encouraged to determine the optimal frequency rate to balance responsiveness with performance.
大概的意思就是:如果鼠标连续的移动,那么浏览器就应该触发多个连续的mousemove
事件。
这就说明了浏览器在其内部计时器允许的情况下,根据用户鼠标的速度来触发mousemove
事件。(当然了, 如果移动鼠标足够快,比如“刷”的一下扫过去,浏览器是不会触发的这个事件的),resize
,scroll
和key*
等事件于此类似。
具体的可以看例子体会下 鼠标滑动
Debounce
DOM事件里的debounce
概念其实是从机械开关和继电器的“去弹跳(debounce)”衍生出来的,基本的思路就是把多个信号的合并为一个信号。
在Javascript中, debounce
函数所做的事情就是:强制某一个函数在某个连续的时间段内只执行一次,哪怕它本来会被调用很多次。即我们希望用户在停止某个操作一段时间之后才执行相应的舰艇函数,而不是在用户操作的过程中,浏览器触发多少次事件,就执行多少次舰艇函数。
比如,在某个5s的时间段内连续移动了鼠标,浏览器就可能会触发几十个(甚至几百个)mousemove
事件, 不使用debounce
的话,监听函数就要执行这么多次;如果对监听函数使用1000ms的“去弹跳”。 那么浏览器就只会执行一次这个监听函数, 而且是在第6s的时候执行的。
那如何实现一个ddebunce
函数呢?
实现
我们debunce
函数接受三个参数, 第一个参数是要“去弹跳”的回调函数func, 第二个参数是延迟的时间wait,第三个参数immediate表示在wait 这个时间区间内做开始执行(immediate = true)还是最后执行(immediate = false)。
1 | /** |
原理
其实原理很简单,debounce
返回了一个闭包, 这个闭包依然会被连续的频繁的调用。但是在闭包的内部, 却限制了原始函数func的执行, 强制func只能在连续操作停止后只执行一次。
调用及例子
调用方式如下:
1 | wwindow.addEventListener('resize', debounce(handle, 1000, false)) |
Throttle
throttle
理解起来更容易,就是固定函数执行的速率
即所谓的节流
。举个例子,正常的情况下,mousemove
的监听函数可能会20ms(假设)执行一, 如果设置200ms的”节流“。那么它就会每200ms执行一次。 比如在1s的时间段内,正常的监听函数可能会执行50(1000/20)次。”节流”的就会执行5(1000/200)次。
我们来看个例子:**例子**无论我鼠标移动的有多快, 我的count 都是匀速(每隔1s)增加。
实现
与debounce
类似, 我们throttle
也接收func
(一个实际要执行的函数),wait
一个执行时间间隔值。
1 | /** |
调用及例子
1 | window.addEventListener('resize', throttle(handle, 1000)); |
throttle
常用的场景是限制resize
和scroll
的触发频率。我们以scroll 为例子**scroll例子 resize例子 **
可视化解释
如果还是不能完全体会debounce
和throttle
的差异, 可以看这个例子 可视化例子
总结
debounce
强制函数在某段时间内只执行一次,throttle
强制函数以固定的速率执行,在处理一些高频率触发的DOM 事件的时候, 它们都能极大提高用户体验。