总结前端性能优化-节流和防抖
前端的节流和防抖是老生常谈的问题,比如我们在滑动滚动条时获取scrollTop的值,或者连续点击按钮一直触发事件,这个时候我们就需要用防抖或节流来控制事件发生的频率
一、防抖的实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p style="height: 1200px;" id="btn">点击</p> <script> var count = 0 var timer = null // 防抖:在限定的时间内连续触发函数时,只触发一次这个函数 //防抖的实现 document.getElementById('btn').addEventListener('click',function(){ if(timer){ // 1s内再点的话走这里,然后下面再创建新的定时器,这样在1s内重复点击他就永远不会执行,直到最后一次点击过了1s后才打印 clearTimeout(timer) } timer = setTimeout(function(){ console.log('被点击次数:',count++) },1000) }) // 关于闭包 // 例1:全局不能访问到变量a function click(){ var aa = 1 console.log(aa,'0') } click() console.log(aa) // 这里会报错,因为aa是在函数的局部作用域中声明的,而函数在执行后函数的作用域和变量会被销毁 // 例2 function click2(){ var aa = 1 function logs(){ console.log(++aa,'10') } return logs } var c = click2() c() // 执行后打印了1 ,因为闭包将logs函数提到了全局执行,logs函数作用域没有被销毁,所以可以正常打印aa, // 下面用闭包来写下防抖 function bounce(fn,delay){ var timer = null return function(){ if(timer){ clearTimeout(timer) } timer = setTimeout(fn,delay) } } function click(){ console.log('被点击次数:',count++) } document.getElementById('btn').addEventListener('click',bounce(click,1000)) // 浏览器滚动防抖实现 function debounce(fn,delay){ let timer = null //借助闭包 return function() { if(timer){ clearTimeout(timer) } timer = setTimeout(fn,delay) // 简化写法 } } // 然后是旧代码 function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); } window.onscroll = debounce(showTop,1000) </script> </body> </html>
一、节流的实现
<script> // 节流的实现 // 上面实现防抖之后,在限定的时间内一直点击,他就一直不会触发,直到他停止点击 // 但我们想让他即使在限定的时间一直点击,它也可以每隔一个时间段内执行一次 let count = 1 function bounceSave(fn,delay){ var timer = null let startTime = new Date(); console.log(startTime) return function(){ clearTimeout(timer) let curTime = new Date(); if(curTime - startTime <= delay){ // 用户连续点击没有超过限定时间1s,会重新开启定时器,再1s内每次都重新开启定时器,那他永远都不会执行,直到else的时候连续点击查过了1s,直接执行fn timer = setTimeout(fn, delay) }else{ // 用户连续点击超过限定时间1s,会直接执行下fn startTime = curTime; fn() } } } function click(){ console.log('被点击次数:',count++) } document.getElementById('btn').addEventListener('click',bounceSave(click,1000))
let count = 0
function bounceSave(fn,delay){
let flag = true
return function(){
if(!flag){
return false;
}
flag = false
setTimeout(()=>{ // 在1s之内再点击,此时flag还是true,就会走上面if语句,直到flag = true就会重新开启定时器
fn()
flag = true
},delay)
}
}
function click(){
console.log('被点击次数:',count++)
}
document.getElementById('btn').addEventListener('click',bounceSave(click,1000))
// 防抖可节流的区别 // 相同点其实都是控制事件发生的频率 // 何时使用函数防抖、何时使用函数节流看需求: // 当只需要处理最后一次触发的事件时,用防抖; // 当用户在操作的过程中过于频繁,但我们需要去控制程序调用的频率(比如例子中时每秒执行一次),用节流 </script>
借鉴blog:https://blog.csdn.net/qq_37860930/article/details/83505547
https://segmentfault.com/a/1190000018428170?utm_source=tag-newest
https://www.h5w3.com/139948.html
加油!