手写防抖和节流
作为性能优化的手段,防抖和节流在前端界颇有名声,虽然网上的代码看起来封装得很复杂,但是经过一层层分解,可以知道这就是很基础的代码技巧,现在我来从最基础的代码模拟实现一遍防抖和节流。
防抖 debounce
思路
防抖的概念就是使用清除定时器来对用户的操作进行限制,相当于一个 cd 条,如果打断了,就不执行(清除定时器)。
比如我现在要做一个 button 按钮,点击两秒钟后打出一句 123,说干就干。
javascript1let btn=document.querySelector('button') 2btn.addEventListener('click',()=>{ 3 setTimeout(()=>{console.log(123)},1000) 4})
没有防抖前效果如下
简单做个防抖
javascript1let btn=document.querySelector('button') 2let timer=null 3btn.addEventListener('click',()=>{ 4 clearTimeout(timer) //每点一次都清除上一次的timer,上一次的就不会执行 5 timer=setTimeout(()=>{console.log(123)},1000) 6 console.log(timer) 7 //这句代码是为了证明获取timer比console早 8 //只要执行了setTimeout就拿到timer了,不用执行参数函数console 9})
效果如下:

优化代码
javascript1let btn=document.querySelector('button') 2 3function debounce(callback, delay) { 4 let timer; 5 return function (...rest) { 6 clearTimeout(timer); 7 const context = this; 8 timer = setTimeout(() => { 9 callback.apply(context, rest); 10 clearTimeout(timer); 11 }, delay); 12 }; 13} 14 15const handler=()=>{console.log(123)} 16btn.addEventListener('click',debounce(handler,1000))
优化代码思路:
逻辑是基于上面的简化版进行的函数封装,就是使用闭包,把 timer 包起来。
然后按照里面的内容拆开写debounce的参数,以上的参数是处理函数 handler(就是 console.log(123))和 delay(时间),如果有更多的业务逻辑,就写更多的参数做封装就行了。
节流 throttle
后来发现节流实际上就是不管用户点多少次,我只执行第一次。
节流与防抖的区别
它跟防抖的关系好比一个法师在施法,如果这个法师不断在施法,但是它的技能是可以被打断的,每打断一次都重新触发施法那就是防抖。
如果这个法师的技能不能被打断,不管你打了多少次,法师都能把刚开始的施法读条 delay 给做完,这就是节流。
示例
没有节流的效果

思路:如何让上面的代码在我设置的时间范围内只跑一次呢?还是使用 setTimeout 实现,如果有一个开关,当开关是打开的时候,就跑代码。如果开关闭合,就不执行代码,跑代码过程中将闭合开关不就行了吗?
节流的效果
代码如下
javascript1let btn=document.querySelector('button') 2const handler=()=>{console.log('初步节流')} 3let toggle=true //设置一个开关 4btn.addEventListener('click',()=>{ 5 if(!toggle){//如果开关是关着的,就return 6 return null 7 } 8 toggle=false //此时函数正在执行,把开关闭合 9 setTimeout(()=>{ 10 handler() //这里是处理业务逻辑了 11 toggle=true //处理完之后把开关打开 12 },1000) 13})
闭包封装
javascript1let btn=document.querySelector('button') 2const handler=()=>{console.log('闭包封装')} 3function throttle(){ 4 let toggle=true //把toggle当做闭包 5 return function (){ 6 if(!toggle){ 7 return null 8 } 9 toggle=false 10 setTimeout(()=>{ 11 toggle=true 12 handler() 13 },1000) 14 } 15} 16btn.addEventListener('click',throttle())
优化代码
javascript1let btn=document.querySelector('button') 2const handler=()=>{console.log('封装函数')} 3 4/* 5参数: 6handler: 执行函数 7delay:时间 8*/ 9function throttle(callback, delay) { 10 let timer; 11 let flag = false; 12 return function (...rest) { 13 if (flag) { 14 return; 15 } 16 flag = true; 17 const context = this; 18 timer = setTimeout(() => { 19 callback.apply(context, rest); 20 clearTimeout(timer); 21 flag = false; 22 }, delay); 23 }; 24} 25btn.addEventListener('click',throttle(handler,2000))
结束~
enjoy!