什么是防抖(debounce)
存在一个事件,触发该事件n秒之后执行一个回调函数,那么这个事件如果n秒之内再一次被触发则重新计时
怎么解决防抖?
下面我用一个相对简单的方式实现防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" name="" id="inp" />
<script>
// 下面开始实现函数防抖
let input = document.querySelector('#inp')
let t = null
input.oninput = function () {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
console.log(this.value)
}, 500)
}
</script>
</body>
</html>
解释
我定义了一个全局变量t,当首次触发oninput事件的时候,t的值为null,不满足if语句,后续执行定时器,后续如果在半秒后没有oninput事件,那么定时器中的回调函数将会被执行。
当我在上一次触发oninput事件后的半秒内又触发了oninput函数,那么此时t的值不为null,满足if语句的条件,这个时候定时器被清除了,之后又重新开始了计时。这样就实现了函数防抖
下面我们升级一下,使用闭包的方式实现函数防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" name="" id="inp" />
<script>
// 下面开始实现函数防抖
let input = document.querySelector('#inp')
// 定义一个防抖函数
let debounce = function (fn, delay) {
let t = null
return function () {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn.call(this)
}, delay)
}
}
input.oninput = debounce(function () {
console.log(this.value)
}, 500)
</script>
</body>
</html>
解释
我定义了一个函数debounce,该函数返回一个匿名函数,并且返回的函数(内层函数)中使用了debounce(外层函数)中的变量——t,形成了闭包。
再触发了oninput事件之后,我执行debounce函数,传入了一个函数和500作为防抖函数debounce函数中定时器的回调和延迟时间。这边需要注意的是,debounce函数在执行之后返回的是一个匿名函数,这个匿名函数就是事件所绑定的回调函数。
还需要注意的是,第29行处的console.log(this.value)中的this原本指向的是window,所以需要在第23行处用call进行一个this指向的转换。因为我们在第28行debounce中所传入的函数就是对应第23行处的fn