防抖理解

前言:这里涉及许多其他知识,不在赘述自行查找其他资料学习,本文只谈防抖和节流的理解。

一、防抖

理解:打个比方,在现实生活中,电梯门的开关和防抖的功能很类似,当第一个人进入电梯后,如果后面没有人了那么电梯就会在5s内关门,如果后面陆续有人进入,每进一个人电梯都会重新计时5s直到最后一个进来的人,这时电梯倒计时5s就可以关门了。按照这个思路,设计以下防抖函数:

 1 function debounce(fn, delay) {
 2     let timer = null;
 3     return function() {
 4         if (timer) {
 5             clearTimeout(timer);
 6         }
 7         let _this = this,
 8             args = arguments;
 9 
10         timer = setTimeout(() => {
11             fn.apply(_this, args);
12         }, delay)
13 
14     }
15 }

 

其中 fn 是我们需要控制的函数,delay是延迟的时间间隔。

只要触发防抖函数,clearTimeOut就会将timer清空,这就像电梯内有人进入就需要重新计时一样,直到最后一个人进入,再计时最后一遍,电梯关门,所以清空timer之后我们需要给timer重新设置一个新的计时器,来模拟最后一个上电梯的人,当最后一次计时结束setTimeOut里的回调函数就会执行,从而达到和电梯这样类似的防抖效果。

这种防抖有个缺点就是他会等到最后一个人进入才会关门也就是说这种防抖不会立即执行待执行的函数,如果只一个人的情况下他还是会计时等待5s再关门。

思考:那么电梯的关门能否改进一下呢?:如果只有一个人进入电梯,那么就立马关门,不再等待。如果后续有人进入的话再设置等待,也就是防抖。

所以按照以上的问题改进以下防抖函数如下:

 1 function debounce(fn, delay, triggleNow) {
 2     let timer = null;
 3     return function() {
 4         if (timer) {
 5             clearTimeout(timer);
 6         }
 7         let _this = this,
 8             args = arguments;
 9         if (triggleNow) {
10             let excute = !timer; //判断是否立即执行
11             timer = setTimeout(() => {
12                 timer = null
13             }, delay);
14             if (excute) {
15                 fn.apply(_this, args);
16             }
17         } else {
18             timer = setTimeout(() => {
19                 fn.apply(_this, args);
20             }, delay)
21         }
22     }
23 }

这样的防抖函数就可以解决刚刚的问题了,加了一个triggleNow这个标志量,可以让用户决定到底要不要立马触发需要被执行的函数。

然而添加了triggleNow标志量后,我们不能直接通过这个标志来判断是否要直接执行fn函数,而是再设置一个标志量excute来判断,这样的好处是可以使代码逻辑和triddle为false时的逻辑保持一致,否则会非常麻烦。如果triggleNow为true的话,那么我们需要对逻辑稍作调整,因为这次我们希望如果第一个人进入电梯之后,立马关门(只触发一次事件时立马执行fn函数),所以我们需要第一次的时时候先执行一次fn,注意if(triggleNow)里的fn函数是否执行是靠excute变量来控制的,所以我们要保证第一次进来的时候excute的值为true,这样就会立马执行fn函数,在后续的过程中继续展现防抖的效果,于是乎在此之前我们需要将timer设置为null,但是不可以直接将timer设为null,而是要设置一个定时器来完成,为什么要样?你想啊,如果直接设为null 那么每次触发防抖函数,excute的值都会为true,fn函数每次都会执行,这样就失去了防抖的功能了,但是通过定时器来设置的话就不一样了,因为timer被设定为了一个新的定时器 ,这个定时器没clearTimeOut之后还会有它的id值,不为null,所以excute的值为false,这样在我们快速点击触发防抖函数时就不会执行fn函数,直到设置的设个定时器倒计时delay毫秒后,timer的值才为null,这样下一次点击才会执行fn,从而实现防抖功能。

 

posted @ 2022-03-25 17:09  grigeorge  阅读(218)  评论(0编辑  收藏  举报