前端面试必备:防抖与节流之防抖及其封装函数

使用带有延迟执行的函数时,触发与之关联的事件即可延迟执行函数,但在延迟的时间内再次或多次地进行事件的触发,延迟时间就会出现失常,对事件的触发及函数的执行都会有很大的影响,所以我们使用函数防抖来解决这个问题。

函数防抖

原理:不断地对回调函数进行延迟。

假设延迟时间为n秒,事件触发后,n秒内再次触发事件,则要重新开始计时,直到延迟时间为n秒时,函数才执行。

这很像生活中的场景,比如乘坐电梯,假设只有一楼有电梯的按键,电梯中间也不能停止,将乘客都送往顶楼。

触发事件:从电梯外按电梯的按键。

延迟时间:电梯开门关门的时间。

函数:电梯带乘客上下楼。

当一个人乘坐电梯时,他会完成整个过程,但,如果他从电梯开门到关门即延迟时间内,又有人按了这个电梯外的按钮乘坐电梯,那么电梯就会进行新一轮的开门关门,直到没有人再按按钮,在开关门的时间过后,电梯才开始送乘客上楼。

使用防抖可以解决很多延迟执行函数的实际问题,一般分为以下两种:

1.初次执行时就进行防抖处理,例如:输入验证。

2.初次执行时不进行防抖处理,函数函数执行完一次才进行,例如:ajax的请求。

带着这两种类型的区别,我们来自己封装一个简单的防抖函数。

防抖的实现

先定义一个函数,其中有三个参数,三个参数分别表示:需要调用防抖函数的函数,延迟的时间,是否第一次就使用防抖。

再定义一个开关t,它类似于一个开关,当它为null的时候,表示没有绑定setTimeout,当它表示绑定的setTineout的id时,如果在规定的时间内,就需要对它进行消除了,达到重新计时的效果。

function debounce(fn,time,triggleNow){
                var t=null;
                          }

此时定义一个函数进行return,其中我们需要将计时器进行消除。

虽然一开始的时候t为null,但后期t的值会发生改变的,先将疑问保留,往下看~~~

  return function(){
                    var _self=this;//保存一下this的指向
                    var args=arguments;
                    if(t){
                        clearTimeout(t)//消除计时器
                    }
                   
                   
                }

 先来处理第一种情况,就是第一次不使用防抖,直接执行需要的函数即可。

if(triggleNow){
                        var exec=!t;//t为null时才能执行函数,这里取非,方便下面的操作
                        if(exec){//取非后这里为真,直接执行即可
                            fn.apply(_self,args)
                        }

由于之前已经将计时器消掉了,我们也不能像第二种情况一样,为它直接加上防抖后的计时器,所以第一次函数执行时,应该拥有原先的计时器。

我们为它添加计时器t。

t=setTimeout(function(){
                         	t=null//延迟预计时间后,将t变为null,才能立即触发
                        },time)

将上面两段代码组合一下。 

if(triggleNow){
                        var exec=!t;//t为null时才能执行函数,这里取非,方便下面的操作
t=setTimeout(function(){
                         	t=null//延迟预计时间后,t为null,下面的exec才能触发
                        },time)

                        if(exec){//取非后这里为真,函数在延迟时间后直接执行了
                            fn.apply(_self,args)
                        }
 }

这样就完成了函数第一次执行按照原先设置的计时器进行延迟,接下来

如果从第一次就进行防抖,那么直接设置新的定时器,由于之前就进行了计时器清除(此时的t就不是null了,clearTimeout可以执行啦~~),所以这部分相当于重新计时。

else{
                        t=setTimeout(function(){
                            fn.apply(_self,args)
                        },time)
                    }

将代码进行改进,变成有返回值res的,并且增加一个remove函数,用来去除防抖。

将整个函数进行展示: 

 function debounce(fn,time,triggleNow){
                var t=null;
                var res;
                var debounced= function(){
                    var _self=this;//保存一下this的指向
                    var args=arguments;//如果返回带参数的函数,就需要保存一下arguments
                    if(t){
                        clearTimeout(t)//消除计时器
                    }
                    if(triggleNow){
                        var exec=!t;//t为null时才能执行函数,这里取非,方便下面的操作
                        t=setTimeout(function(){//计时器之前进行清除了计时器,所以这时候要加上
                            t=null//延迟预计时间后,t还是应该为null,才能立即触发
                        },time)
                        if(exec){//取非后这里为真,直接执行即可
                            res=fn.apply(_self,args)
                        }
                    }else{
                        t=setTimeout(function(){
                           res= fn.apply(_self,args)
                        },time)
                    }
                    return res;
                }
              
                debounced.remove=function(){
                    clearTimeout(t);
                    t=null
                }
                return debounced
            }

以上就是一个完整的事件防抖的封装函数了。

 

节流部分:前端面试必备:防抖与节流之节流及其封装函数

对文章有意见或建议的请留言。

            function debounce(fn,time,triggleNow){//三个参数分别表示:需要调用防抖函数的函数,延迟

 

猜你喜欢

转载自blog.csdn.net/weixin_42309926/article/details/108161713