最近去面试,面试官问我防抖和节流。前几天看过手写代码,但是不会写。有时候我在想是不是我太笨了。回到防抖的话题,先不说概念。按照我自己的理解,单反是有防抖机制的。因为人拿着单反会手抖(单反很重),按下快门的一瞬间,照片会模糊,所以有防抖机制,防止新手拍出模糊的照片。单反中的防抖就是防止晃动,让人拍出清晰的照片。JavaScript中的防抖是干什么用的?同样,它的作用也是防抖。想象一下,当你频繁触发一个事件时,会造成不必要的性能损失,那么让事件停止触发后再触发,从而降低一些性能。防抖的定义防抖就是延迟执行。您一直在操作触发事件,但没有执行。停止操作时,等待多少秒再执行。也就是说,无论事件触发的频率如何,都必须在事件触发后n秒后执行。如果事件触发n秒后再次触发事件,则以新事件的事件为准,n秒后执行。简而言之就是触发事件后n秒内你没有触发事件才会执行。手写防抖根据定义,我们知道它会在n秒后执行,所以我们用一个定时器来实现:functiondebounce(event,wait){lettimer=null;返回函数(...args){clearTimeout(timer);//清除setTimeout使其回调函数不执行timer=setTimeout(()=>{event.apply(this,args)},wait)}}代码很简单,就是当事件还在triggered,是清空timer,这样n秒后执行,但是这种写法第一次不会立即执行,为了健壮性,需要加第三个参数flag来判断是否是第一次执行,判断是否立即执行。functiondebounce(event,wait,flag){lettimer=null;returnfunction(...args){clearTimeout(timer)if(!timer&&flag){事件。apply(this,args)}else{timer=setTimeout(()=>{event.apply(this,args)},wait)}}}防抖场景窗口大小变化,调整样式window.addEventListener('resize',debounce(handleResize,200))搜索框,输入后1000毫秒内搜索debounce(fetchSelectData,300)表单验证,输入1000毫秒后验证debounce(validator,1000)。防抖库的两大工具库都有防抖源码可供参考:lodash-debounce。下划线去抖动。顾名思义,节流就像在事件不断触发的过程中,控制一个水阀在固定的时间内执行一个事件。因为手写节流是在固定的时间内执行一次,所以我们有两种实现方式,一种是使用时间戳,一种是使用定时器。时间戳函数throttle(event,wait){letpre=0;returnfunction(...args){if(newDate()-pre>wait){//当n秒内没有重复时pre=newDate();event.apply(this,args)}}}可以通过时间戳实现节流,但是不会执行最后一个事件。定时器函数节流阀(事件,等待){让定时器=null;returnfunction(...args){if(!timer){timer=setTimeout(()=>{timer=null;event.apply(this,args)},wait)}}}使用定时器实现节流。虽然上次可以触发,但是第一次不会触发。时间戳+定时器。要解决第一个和最后一个触发器,请将两者结合起来。functionthrottle(event,wait){让pre=0,timer=null;返回函数(...args){if(newDate()-pre>wait){clearTimeout(timer);定时器=空;pre=newDate();event.apply(this,args)}else{timer=setTimeout(()=>{event.apply(this,args)},wait)}}}节流场景滚动scrollwindow.addEventListener('scroll',throttle(handleScroll,200))inputdynamicsearchthrottle(fetchInput,300)节流御库lodash-throttle。下划线油门。总结一下防抖:只执行最后一次。事件持续触发,但函数直到事件停止触发后n秒才执行。节流:控制执行频率。连续触发,每n秒执行一次函数。对比图:
