本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Prerequisite: JS函数、setTimeout
什么是debounce?
debounce防抖,是一个被广泛应用于交互应用中的技术,用来过滤一串快速发生的无效事件(抖动)。
举个例子:一个输入框,我们希望用户输入完成以后自动发起搜索。简单的方法是,监听用户的输入事件,每次用户改变输入,我们就发起请求查询用户的输入内容。然而,这样做很明显会造成极大的浪费。用户输入hello,实际上我们已经发起了五次请求,分别查询
h
he
hel
hell
hello
那么,有没有更好的方法能恰好在用户停止输入(一段时间)以后才发起查询请求呢?这就是debounce防抖,过滤一系列快速发生的事件,只保留一串事件中最后一次触发的事件。
代码实现
debounce函数,可以将任何函数封装为“防抖”函数。先看代码,解释在后面!
function debounce (func, timeout = 300) {
let timer
return (...args) => {
clearTimeout(timer)
timer = setTimeout(() => { func.apply(this, args) }, timeout)
}
}
将实际执行的函数作为第一个参数传入debounce,保存封装的“防抖”函数。调用时调用“防抖”函数即可。
使用案例:
const print = debounce(m => console.log(m), 500)
print('hello')
print('can you see this?')
print('hi')
setTimeout(() => { print('amazing!') }, 1000)
控制台的输入结果如下:
hi
amazing!
前三个print连续触发,只有最后一个被实际执行。停顿1秒超出timeout以后,再次触发即可重新执行。
解析
function debounce (func, timeout = 300) {
函数头部,接受两个参数,第一个为实际执行的函数,第二个为timeout毫秒数。
let timer
定义变量timer用于保存计时器。请注意这个变量的定义位置,它在返回的“防抖”函数之外。也就意味着每次调用的“防抖”函数将共享这个变量。
return (...args) => {
返回防抖函数头部,接收任意参数表,因此适用于任何被封装的函数。
clearTimeout(timer)
无论以前是否有触发“防抖”函数,清除掉以前的触发留下的计时器。若上次触发还没有实际执行(在timeout时间内),则上次触发将被打断,不会被实际执行。
timer = setTimeout(() => { func.apply(this, args) }, timeout)
设置计时器为本次触发的内容,若不被另一个触发打断(clearTimeout),将在timeout时间以后被实际执行,触发时传入的参数也将被传入到实际执行的函数中。