关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
一、使用时间戳
让我们来看第一种方法:使用时间戳。
当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {
// 上一次执行 fn 的时间
let previous = 0
// 将 throttle 处理结果当作函数返回
return function(...args) {
// 获取当前时间,转换成时间戳,单位毫秒
let now = +new Date()
// 将当前时间和上一次执行函数的时间进行对比
// 大于等待时间就把 previous 设置为当前时间并执行函数 fn
if (now - previous > wait) {
previous = now
fn.apply(this, args)
}
}
}
// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)
+new Date()
看到+new Date(),有点不熟悉,所以特此记录一下;
js在某个数据类型前使用‘+’,这个操作目的是为了将该数据类型转换为Number类型,如果转换失败,则返回NaN;
例子 :
+'2'+1 // 3
+[1] // NaN
+new Date() 会调用Date.prototype 上面的 valueOf方法,根据
MDN:developer.mozilla.org/en-US/docs/…
new Date().getTime() === new Date().valueOf() //true
下面的例子返回效果等同:
+new Date();
new Date().getTime();
new Date().valueOf();
new Date()*1
二、使用定时器
接下来,我们讲讲第二种实现方式,使用定时器。
当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器,这样就可以设置下个定时器。
function throttle(func, wait) {
var timeout;
return function() {
context = this;
args = arguments;
if (!timeout) {
timeout = setTimeout(function(){
timeout = null; //在setTimeout里面,也即是到达时间后执行
func.apply(context, args)
}, wait)
}
}
}
当鼠标移入的时候,事件不会立刻执行,晃了 3s 后终于执行了一次,此后每 3s 执行一次,当数字显示为 3 的时候,立刻移出鼠标,相当于大约 9.2s 的时候停止触发,但是依然会在第 12s 的时候执行一次事件。
所以比较两个方法:
第一种事件会立刻执行,第二种事件会在 n 秒后第一次执行
第一种事件停止触发后没有办法再执行事件,第二种事件停止触发后依然会再执行一次事件