为什么会有函数防抖与节流这个概念
- JavaScript是事件驱动的,大量的操作会触发事件,加入到事件队列中处理。
- 而对于某些频繁的事件处理会造成性能的损耗,我们就可以通过防抖和节流来限制事件频繁的发生;
- 防抖和节流函数目前已经是前端实际开发中两个非常重要的函数,也是面试经常被问到的面试题。
- 但是很多前端开发者面对这两个功能,有点摸不着头脑
引用一个经典的例子
我们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会形成一个连贯的动画,所以在电影的播放(以前是,现在不知道)中基本是以每秒 24 张的速度播放的,为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候,100 张就会显得很浪费资源。再举个栗子,假设电梯一次只能载一人的话,10 个人要上楼的话电梯就得走 10 次,是一种浪费资源的行为;而实际生活正显然不是这样的,当电梯里有人准备上楼的时候如果外面又有人按电梯的话,电梯会再次打开直到满载位置,从电梯的角度来说,这时一种节约资源的行为(相对于一次只能载一个人)。 —— 引自大板栗函数节流与函数防抖
哪些场景需要防抖与节流
- 浏览器scroll或者界面resize时候会频繁触发事件,在某些场景可能需要
- 页面中有个grid表格数据,当我们下拉的时候调用Api获取更多的数据,此时就需要节流
- input输入框值去请求数据的时候,就需要防抖
- 一些keyup、keydown和keypress事件可能也需要
这种耗费性能的事情,很可能造成浏览器的卡顿,甚至崩溃,所以我们可以使用防抖与节流来处理
函数防抖(Debounce)
实质:设置一个定时器,当触发了事件之后,就销毁这个定时器,重新开启一个定时器,当没有触发事件后,到达指定的时间,就执行这个定时器。
举个例子:按下一个弹簧,每次按下去一点点,只有你松手的时候弹簧才会弹起,弹起只会操作一次,但是往下按操作了很多次
方法实现:(模拟界面滚动实现)
//界面
<body style="background: seagreen;height: 1800px;">
<div>
<h2>我是一个防抖函数</h2>
<br />
<br />
</div>
</body>
//实现
var timer=null
//防抖
window.onscroll = function(){
clearInterval(timer)
timer = setTimeout(()=>{
console.log(new Date().toLocaleDateString())
},300)
}
解释:定义一个定时器,设置一个界面滚动事件,我们知道每次界面滚动都会触发一个滚动事件,所以我们需要使用一个定时器来做防抖,只有滚动过了0.3s才执行
函数节流(Throttle)
实质:无论我们触发了多少次事件,在我们规定的时间内只触发一次。防抖有一个问题,那就是如果事件一直在触发,那么执行函数永远都得不到执行,此时我们可以用节流来解决
throttle:事件触发后执行函数执行期间内事件再次触发,执行函数将不会执行,等规定时间之后事件触发,执行函数方可再次执行。
方法实现:(模拟界面滚动实现)
//界面
<body style="background: seagreen;height: 1800px;">
<div>
<h2>我是一个防抖函数</h2>
<br />
<br />
</div>
</body>
//实现
//节流
var control = true
window.onscroll = function () {
if (!control) {
return
}
control = false
timer = setTimeout(() => {
control = true
console.log(new Date().toLocaleDateString())
clearTimeout(timer)//清除
}, 5000)
}
解释:定义一个定时器,在触发一次事件后,在定时器的规定时间内不能在触发该事件,等到定时器执行了之后,该事件又可以再次被执行