去抖(debounce)与节流(throttle)
效果
使用效果参考
See the Pen debounce and throttle by Erioifpud (@erioifpud) on CodePen.
debounce
debounce 也就是我们常说的去抖,用于阻止短时间内的频繁操作。
举个例子,页面上有一个刷新按钮,每次点击都会发起请求去获取最新数据,频繁点击会发起多次请求,实际上有意义的只有最后一次,那么阻止“非最后一次”操作这样的行为就是去抖。
去抖函数实现起来非常简单,或许我们在平常的业务中就已经实现过了,但是自己没意识到:
function debounce (func, wait) {
// 这里做个类型检查
let timer
return function (...args) {
if (timer) {
clearTimeout(timer)
timer = setTimeout(() => {
timer = null
func.apply(this, args)
}, wait)
return
}
timer = setTimeout(() => {
func.apply(this, args)
timer = null
}, wait)
}
}
debounce
是一个高阶函数,我们将需要去抖的函数传给他,他返回的就是包装后的函数。
timer
记录的是定时器的 id,我们根据这个 id 来判断上一个定时器(时差是否超过 wait)是否执行结束,所以内部函数也使用了这个 timer
,这里形成了一个闭包,保证 timer
不会因为 debounce
执行结束而被回收。
由于 func
是在 setTimeout
中被调用的,所以在上一个定时器还没完成的时候,需要使用 clearTimeout
清除定时器,不然先前的定时器到时间了依然会调用 func
。
throttle
throttle 是节流的意思,和 debounce 不太一样,虽然也是减少频繁操作的,但他并不会完全阻止操作执行,反而是每隔一定时间放行(执行)一次。
举个例子,使用搜索引擎输入关键字的时候会出现自动补全,但并不是每输入一个字网站都会发一个请求去获取候选词列表的,多数是在你保持输入的情况下,每隔 n 秒请求一次,这样的操作就是节流。
function throttle (func, wait) {
// 这里做个类型检查
let timer
return function (...args) {
if (timer) {
return
}
timer = setTimeout(() => {
timer = null
func.apply(this, args)
}, wait)
}
}
相比 debounce
,throttle
的代码就简单很多了,timer 还是记录上一个定时器是否执行结束,结束了就可以开始一个新的计时器,没结束就等待。