防抖与节流
1. 用途
防抖和节流是针对响应跟不上触发频率这类问题的两种解决方案。
举例来说,一个点击事件会发起一次请求,用户拼命去快速点击,就会发起许多次请求,这显然不合理,防抖节流就是限制这种行为。
注意:防抖是控制次数,节流是控制频率
2. 防抖(debounce)
防抖是无论触发多少次事件,只执行最后一次;
具体来说就是:规定时间内回调函数只能执行一次,如果在规定时间内又触发了该事件,则会重新开始算规定时间
案例:
点击.box元素,1s后输出123;在点击了之后,1s内再点多少次,都以最后一次点击为准重新开始出现计时1s,然后输出一次123
function debounce(fn,waitTime){
let timeout =null
return function(){
if(timeout!==null){
clearTimeout(timeout)
}
timeout=setTimeout(fn,waitTime)
}
}
function cs(){
console.log(123)
}
document.querySelector(".box").addEventListener("click",debounce(cs,1000))
3. 节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。通俗来说就是假如规定点击之后1s内发起一次请求,这1s内无论点多少次,无论请求有没有完成,都不会再发起请求
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
1) 时间戳版:
function throttle(fn,waitTime){
let prev=Date.now()
return function(){
let now=Date.now()
if(now - prev > waitTime){
fn()
prev=Date.now()
}
}
}
function cs(){
console.log(123)
}
document.querySelector(".box").addEventListener("click",throttle(cs,1000))
</script>
每次执行fn函数都会更新prev用来记录本次执行的时间,下一次事件触发时判断时间间隔是否到达预先的设定,重复上述操作。
2) 定时器版:
function throttle(fn,waitTime){
let timeout=null
return function(){
if(!timeout){
fn() //放在这可以先执行,不用等1s
timeout=setTimeout(function(){
//fn() 放这里是1s后执行
timeout=null;
},1000)
}
}
}
function cs(){
console.log(123)
}
document.querySelector(".box").addEventListener("click",throttle(cs,1000))
4. vue项目中遇到的案例
1) 需求:点击一个div元素,发起请求,获取到数据,之后弹出弹窗,渲染弹窗
2)问题:如果不进行防抖节流,一直点击div元素,就会一直发起请求;如果使用定时器的方法来实现防抖节流,无法掌握请求响应时间与设置的时间之间的长短问题,长了用户觉得反应慢,短了又会发起请求
3)解决:
- 在data中设置一个变量status=true
- 开始执行函数就将变量重新赋值为false,接着执行请求函数,此时再触发点击事件,也不能满足条件发起请求函数
- 请求函数使用async和await,在发起请求,处理完数据之后,再将status重新赋值为true,这样点击事件又能执行请求函数
- 这样点击之后,弹窗没出来之前,只能触发一次请求函数,直到请求函数执行完毕,才能再次触发,时间刚刚接上,比定时器要灵活
//请求函数
async fn(){
//发起请求
let data=await axios(xxxxxx)
//处理数据
xxxxxx
//将变量status=true
this.status=true
}
//点击函数
clickEvent(){
//第一次是true,执行请求函数
if(this.status){
//一开始执行就将变量status=false
this.status=false
//执行请求函数
this.fn()
}
}