节流
节流就是当你持续触发事件时,每隔一段时间只会执行一次事件。
根据首次是否执行以及结束后是否执行,效果也不相同,实现的方式也有所不同。这里使用leading代表首次是否执行,trailing代表结束后是否在执行一次。
目前节流有两种主流实现方式:
1. 使用时间戳
2. 设置定时器
使用时间戳
使用时间戳也就是说,当事件被触发的时候,我们取出当前的时间戳,然后减去之前的时间戳,如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于就不执行。
代码形式如下:
1 | <div id="container"></div> |
1 | #container{ |
1 | function throttle(func, wait) { |
效果如下:
当鼠标移入的时候,事件立即执行,相比没使用节流之前鼠标移动一下就会触发一次,现在是当鼠标移入时立即触发一次,在设定的1秒时间内无论怎么移动都不会再次执行,
使用定时器
第一种使用了时间戳,现在换成定时器来试试
1 | function throttle(func, wait) { |
比较下这两种实现的区别:
1. 第一种事件会立刻执行,第二种事件会在n秒后第一次执行。
2. 第一种事件停止触发后没有办法再执行事件,第二种停止触发n秒后,最后一次执行事件。
综合上述两种方式,我们需要一个:触发事件会立即执行,停止触发后n秒还会最后执行一次的throttle函数
1 | function throttle(func, wait) { |
上述的功能需求已经完成。
优化
需求: 有时我们也希望无头有尾,或者有头无尾。根据传进来的值判断到底是那种效果。
这里约定:
- leading: false 表示禁用第一次执行
- trailing false 表示禁用停止触发的回调
1 | function throttle(func, wait, options) { |
取消
在debounce中,添加一个cancel方法
1 | throttle.cancel = function(){ |
注意
undersocre的实现中有这样一个问题:leading: false
和 trailing: false
不能同时设置
如果同时设置的话,当你将鼠标移除的时候,因为trailing设置为false,停止触发的时候不会设置定时器了,所以只要再过了设置的时间,在移入的话,就会立刻执行,就违反了leading:false
,bug就出来了,所以,这个throttle只有三种用法:
1 | container.onmousemove = throttle(getUserAction, 1000); |