什么是防抖和节流?
原创
2019-7-19
08:39
编辑于
2022-6-17
15:39
背景
前端为啥会出现这两个名词?在连续触发事件的场景下,比如监听鼠标移动,用户输入,滚动条滚动,回调会不断连续触发,但是实际情况是不需要连续触发,当然需要获取鼠标位置的场景除外,连续执行回调不仅没必要,而且有性能问题。因此为了解决这种场景下连续触发的问题,才有了防抖和节流。
防抖
设定的延迟时间内,如果事件没有再次被触发,那么执行回调,如果事件再次被触发,那么重新计时。
防抖和节流一般用于事件绑定。
document.addEventListener('scroll', callback)
那么最终应该是返回一个函数(callback),用于绑定事件。大致应该长这样。
function debounce(fn){
return function() {
fn()
}
}
fn 事件触发要执行的代码
上面说了我们需要设定延时,即延时执行 fn。因此需要用上 setTimeout。
function debounce(fn, delay) {
return function() {
setTimeout(function() {
fn()
}, delay)
}
}
上面的代码并没有解决事件再次触发,重新计时的问题,因此我们需要将定时器 id 保存下来,再次触发的前清除定时器。
function debounce(fn, delay) {
var timeoutId = null
return function() {
clearTimeout(timeoutId)
timeoutId = setTimeout(function() {
fn()
}, delay)
}
}
在 setTimeout 中执行,会丢失当前运行时的上下文(this),因此这里不能直接运行,需要做 this 绑定。另外事件回到的参数也丢失了(事件绑定的回调是 debounce 返回的函数,不是 fn),因此在 fn 中不能访问事件回调参数 event 了,因此需要把参数传给 fn。
function debounce(fn, delay) {
var timeoutId = null
return function() {
var context = this
var args = arguments
clearTimeout(timeoutId)
timeoutId = setTimeout(function() {
fn.apply(context, args)
}, delay)
}
}
节流
在设定的时间内,不管事件触发多少次,只认第一次事件触发。不同于防抖,节流不会重新计时,严格按照设定的时间执行回调。代码大致和上面相同,就不按步骤讲解了。
function throttle(fn, delay) {
var timeoutId = null
return function() {
var context = this
var args = arguments
if (!timeoutId) {
timeoutId = setTimeout(function() {
fn.apply(context, args)
timeoutId = null
}, delay)
}
}
}
参考
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/5

关注我的公众号