节流与防抖在我看来其实是为了解决一类相同的场景的不同解决方案,就是在一些用户会频繁触发的事件例如输入框输入的同时需要实时的请求接口检查,如果不做限制的话会导致大量的请求发出而有可能会造成一些请求失败导致后续不可预估的问题。而在有些涉及到视图变化的操作例如鼠标移动窗口移动之类的事件的时候如果不采取合理的措施就可能会造成页面的卡顿甚至崩溃,而节流与防抖就应运而生了。
节流就像是一个水龙头,无论连接其背后水管里面的水流多大,水龙头的阀门只让水一秒一滴,那么水就是一秒一滴的速度出来。那么应用到代码中就是在一个时间段内无论触发了多少次函数只有一次生效,一秒生效一次,所以节流特点在连续高频触发事件时,动作会被定期执行,响应平滑。
function throttle(func, wait) {
let timer
return function() {
// 如果定时器存在,则不执行,这里始终只有一个定时器
if (!timer) {
timer = setTimeout(() => {
// 设置定时器方便下次执行
timer = null
// 这个this指向的是此处这个return函数,arguments是一个对象类似于数组(类数组对象,有长度),是函数中可用的局部变量
func.apply(this, arguments)
}, wait)
}
}
}
let demo = function () {
console.log(new Date().getSeconds())
}
setInterval(throttle(demo, 1000), 10)
具体函数实现如上,我们先定义一个 throttle
函数,它接受两个参数,我们要执行的函数和节流的这个时间,在这个例子中我们执行的函数为 demo
输出当前时间秒,节流的时间为1s, 然后具体回到 throttle
中来,当触发这个函数的时候我们设置一个定时器,然后在callback function中如果定时器存在的话就不执行,存在就设置定时为空然后执行我们传入函数,这个定时器设置的等待时间 wait
就是我们传入的这个时间,这里不可以用 clearTimeout
来清除定时器,因为整个函数只有一个定时器,清掉就没了。而函数中的 func.apply(this, arguments)
这个,首先 apply
是 function
自带的方法,就是相当于调用你的这个函数,它接受两个参数 this, args
,这个 this
就是你执行的这个函数的 this
, 所以我们这里传入相同的 this
,args
则是这个函数里面的可用的变量,同上我们也是传相同的。所以整个节流的函数实现基本就是如此了。
1,鼠标频繁点击触发的事件
2,滚动监听事件
3,...
节流是在一个1s执行一次,而防抖则是在开始我执行一次,等到这个1s之后我才执行第二次,但是如果你在1s内又执行了这个事件,那么我就以你新的执行这个时间为准再等1s再执行,总之,就是要等你触发完事件1s内不再触发事件,我才执行,所以可能会出现一种情况,如果你执行这个事件的间隔事件小于我设置的这个等待时间,那么你可能只会执行一次而接下来会一直等待。
function debounce(func, wait) {
let timer
return function () {
clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, arguments)
}, wait)
}
}
let fun1 = function () {
console.log('this is fun1')
}
let fun2 = function () {
console.log('this is fun2')
}
setInterval(debounce(fun1, 500), 1000)
setInterval(debounce(fun2, 2000), 1000)
具体函数实现如上,其实我觉得防抖比节流要好理解一点,因为就是直接一个定时器,如果之前存在这个定时器,那么我就把它销毁,然后执行我新的定时器,而在例子中,我使用了两个1s一次的循环器, 第一个是我 debhounce
的等待时间是500毫秒, 第二个是2000毫秒,那么就会因为第一个循环器的原因他一直在执行 debounce
而导致第二个会一直等待下去。所以防抖函数也实现了。
1,输入框的持续输入
2,鼠标拖拽滑动事件
3,...
当然相应的场景对应使用的方法并不是一成不变的,只有在合适的场景使用合适的方法才能更好的实现我们所需要的功能。