什么是防抖和节流
防抖和节流都是为了项目优化而出现的,官方没有做出具体定义,他们的出现主要是为了解决一些短时间内连续执行的事件带来性能上的不佳和内存的消耗巨大等问题;像这类事件一般像 scroll keyup mousemove resize等等,短时间内不断的触发,在性能上消耗是非常大的,尤其是一些改变DOM结构的操作。
防抖和节流的作用都是防止函数多次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的情况下只会调用一次,而节流的情况会每隔一定时间(参数wait)调用函数。
定义
- 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
函数防抖
原理
当持续触发一个事件时,在n秒内,事件没有再次触发,此时才会执行回调;如果n秒内,又触发了事件,就重新计时。
生活中的实例
比如在坐电梯时,第一个人进入电梯后,如果10s内没有人再进入电梯,电梯门就会关上,但是在10s内有一个人进入了电梯,则电梯就会重新计时,直到电梯门关上,这就完成了一次防抖
适用场景
- search远程搜索框:防止用户不断输入过程中,不断请求资源,n秒内只发送1次,用防抖来节约资源。
- 按钮提交场景,比如点赞,表单提交等,防止多次提交。
- 监听resize触发时, 不断的调整浏览器窗口大小会不断触发resize,使用防抖可以让其只执行一次。
代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>防抖</title>
</head>
<body>
<button onclick="debounce(fn1,1000)">防抖</button>
</body>
<script>
// timer用来记录当前定时器
let timer = null
//防抖函数
function debounce(fn, delay = 300) {
//参数fn是需要执行防抖的事件,delay是触发防抖的时间间隔
// 判断如果存在定时器,则清除当前定时器
if (timer) {
console.log('触发防抖')
clearTimeout(timer)
}
// 重新计时
timer = setTimeout(() => {
fn()
// 事件执行完毕将timer赋为null
timer = null
}, delay)
}
function fn1() {
console.log('执行防抖事件')
}
</script>
</html>
效果演示
函数节流
原理
当频繁的触发一个事件,每隔一段时间, 只会执行一次事件。
生活中的实例
在一段拥挤的道路,有很多密密麻麻的车辆,这时候就要进行交通管制了,交警要合理控制车流量,防止堵车,其实就是规定了每段时间间隔能进入的车辆数目,比如每一分钟就放20辆车通行,之前来的车都会被阻拦,这就完成了节流。
适用场景
- 拖拽场景:固定时间内只执行一次, 防止高频率的的触发位置变动
- 监听滚动事件:实现触底加载更多功能屏幕尺寸变化时, 页面内容随之变动,执行相应的逻辑
- 射击游戏中的mousedown、keydown时间(单位时间只能发射一颗子弹)
代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>节流</title>
</head>
<body>
<button onclick="throttle(fn2,1000)">节流</button>
</body>
<script>
//定义一个节流阀
let isLoading = false
//节流函数
function throttle(fn,delay=300) {
//fn 是要执行节流的函数,delay是节流时间
// 判断当前是否处在节流时间内
if (isLoading) {
console.log('触发节流')
return
}
isLoading = true
//经过delay时间后触发时间并将节流阀关闭
setTimeout(()=>{
fn()
isLoading=false
},delay)
}
function fn2() {
console.log('节流事件执行')
}
</script>
</html>