为什么要防抖
在前端开发中会遇到一些频繁的事件触发,比如:
- window 的 resize、scroll
- mousedown、mousemove
- keyup、keydown
……
|
|
|
|
因为这个例子很简单,所以浏览器完全反应的过来,可是如果是复杂的回调函数或是 ajax 请求呢?假设 1 秒触发了 60 次,每个回调就必须在 1000 / 60 = 16.67ms 内完成,否则就会有卡顿出现。
为了解决这个问题,一般有两种解决方案:
- debounce 防抖
- throttle 节流
防抖原理是什么
防抖的原理就是:你尽管触发事件,但是我一定在事件触发n秒后才执行,如果你在一个事件触发的n秒内又触发了这个事件,那我就以新的事件的时间为准,n秒后才执行,总之,就是要等你触发完事件n秒内不再触发事件,我才执行。
防抖的实现
第一版
|
|
还是开始的例子测试:
|
|
现在是移动完1000ms之后才执行getUserAction
事件:
绑定this
如果我们在getUserAction
函数中打印this
,在不使用防抖的时候,this
的值为:
|
|
但是用了刚才实现的防抖函数之后,因为setTimeout
是挂载在window
对象上的,所以getUserAction
中的this
会指向Window
对象。所以我们需要将this
指向正确的对象。
|
|
现在this
已经可以正确指向了。
event对象
事件监听的回调函数的第一个参数是事件对象
,现在我们要把这个对象传给防抖函数中的func
:
|
|
立即执行
上面封装的防抖函数属于延迟执行的防抖函数,只在事件结束后最后调用。比如使用搜索引擎输入问题的时候,我们希望用户输入完最后一个字才调用查询接口,这个时候适用延迟执行的防抖函数。
考虑一个新的需求:需要事件触发后立刻执行函数,然后停止触发事件n秒后才能重新触发。
加一个immediate
参数判断是否立刻执行:
|
|
返回值
getUserAction
可能是有返回值的,所以我们也要返回函数的执行结果,但是当防抖函数是延迟执行的时候,因为使用了setTimeout
,我们return的结果会一直是undefined
,所以我们只在立即执行的防抖函数下返回函数的执行结果。
|
|
取消
最后我们希望增加一个能取消防抖,可以立刻重置延迟时间,初始化防抖函数的功能。
|
|
防抖的出处
节流
节流的原理
节流的原理很简单:如果你持续触发事件,每隔一段时间,只执行一次事件。
根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。我们用leading代表首次是否执行,trailing代表结束后是否再执行一次。
使用时间戳
|
|
使用定时器
|
|