Spirit防抖函数underscore和节流函数lodash怎么用(underscore,开发技术)

时间:2024-05-02 15:21:14 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

防抖函数和节流函数的区别

防抖函数:是指触发了一个事件,在规定的时间内,如果没有第二次事件被触发,那么他就会执行.换句话讲,就是说,如果不断有事件被触发,那么规定的执行时间将会被不断推迟

Spirit防抖函数underscore和节流函数lodash怎么用

节流函数:指的是在规定时间内,你无论触发多少次事件,你也只会执行一次.我举个生活中的例子,就很好理解了.王者荣耀这个游戏可能很多人多玩过,每个英雄都有自己的技能,在我们点击一次后,该技能会进入冷却时间,即使我们点的再快,该技能在冷却时间好之前也只能触发一次(我们第一次点击的时候)

Spirit防抖函数underscore和节流函数lodash怎么用

防抖函数的实现

我将实现防抖函数的四个功能,希望大家能一步步的跟着来,循序渐进,相信大家一定会有收获的

基本实现

我们可以想下,要想一个事件在规定时间过后执行,在JS中该怎么实现

好 时间到

定时器,小伙伴们肯定都知道的吧

触发事件,在一定时间后执行,这个可以使用定时器解决了.

那么 接下来还有一个问题 在触发事件后,再触发事件,该如何让他推迟执行呢?

如果规定时间内,再触发的话,我们就把之前创建的定时器删除不就好了,对不对?

这样是不是就解决了我们的问题,好,我们现在来写下代码,怕大家有点不明白

functiondebounce(fn,delay){//定义一个定时器lettimer=null;//每次触发的时候清空上一次的定时器const_debounce=function(){if(timer)clearTimeout(timer);//根据传进来的延时执行timer=setTimeout(()=>{fn();},delay)}return_debounce;}

这段代码还是比较容易的吧,相信小伙伴们肯定都懂了

但是这段代码还是有点问题,我们来调用下第三方库的underscore的防抖函数

<body><button>取消</button><inputtype="text"><scriptsrc="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script><script>constbtn=document.querySelector("button");constinput=document.querySelector("input");letcount=0;functiontest(event){//注意这里的this和eventconsole.log(`发送${++count}网络请求`,this,event);return"我是返回结果";}input.oninput=_.debounce(test,2000);</script></body>

我们打开浏览器调试,看下输出结果

Spirit防抖函数underscore和节流函数lodash怎么用

可以看到this和Event输出是没有任何问题的.

再来看看我们的输出

Spirit防抖函数underscore和节流函数lodash怎么用

你会发现 this是window了 而Event是undefined.

这是为什么呢?

这是因为 我们写的代码没有对this进行一个绑定,同时也没有将DOM元素的event接收

fn()直接执行 这时候的this是直接指向window的

functiondebounce(fn,delay){lettimer=null;//使用剩余参数接收所有的参数DOM在调用这个函数的时候,我们就能接收到event了const_debounce=function(...args){if(timer)clearTimeout(timer);timer=setTimeout(()=>{//注意我们使用apply进行一个换绑,绑到执行这个的DOM元素上fn.apply(this,args);},delay)}return_debounce;}

至此,我们这个防抖函数的基本实现就没有任何问题了

看到这里的小伙伴们,你们真不错

这个基本实现 拿来应付面试已经够了,接下来我们还有一些额外的功能要实现,想看的可以继续往下看了,现在不想看的也可以收藏下,以后来看.

立即执行

在某些应用场景下,比如搜索的时候,你输入第一个字符的时候,他就会联想出一系列的字符,他不会等待一段时间后再去执行,而是会立马执行,我们接下来实现下这个功能

首先,立即执行这个功能,我们可以将它交给用户来决定是不是要使用这个功能

debounce(fn,delay,immediate=false)

我们以参数的形式传递,默认是关闭的

好,我们现在来看下代码实现

functiondebounce(fn,delay,immediate=false){lettimer=null;//代码规范我们最好不要修改用户传递进来的参数//所以我们在下面声明了一个变量用于控制letisInvoke=false;const_debounce=function(...args){if(timer)clearTimeout(timer);//如果immdiate为true//isInvoke取反为trueif(immediate&&!isInvoke){//会立马执行一次fn.apply(this,args);//同时将isInvoke设置为true,防止下次触发的时候又再次触发立即执行isInvoke=true;}else{//第一次触发结束立即执行后//isInvoke会限定在定时器中输入结束后才会重新刷新isInvoketimer=setTimeout(()=>{//剩下的操作在规定时间内会等待定时器结束fn.apply(this,args);//同时重新刷新inInvokeisInvoke=false;},delay)}}return_debounce;}

好,这一块还是比较简单的吧,相比大家应该看懂了,如果有什么不懂的地方,欢迎评论区留言,我看见了就会回答的

那么我们开始下一个篇章的 如果用户输入之后 不想让他请求呢 这时候我们就需要一个取消功能了,对,我们接下来就是要实现取消功能了

取消功能

我们该如何在剩余的时间内取消请求呢?

对 没错! 清空定时器

我们只需要在我们返回的函数上加个静态方法 给用户提供个取消功能即可

我们来看下代码实现

//给返回的这个函数添加一个静态方法用于取消请求_debounce.cancel=function(){if(timer)clearTimeout(timer);}

是不是很简单呢? 就这么简单一行代码 取消功能就完成了

好,我们还有最后一个功能需要实现的 那就是如果开发者想要拿到请求后的返回结果的话,我们现阶段的防抖函数能不能做到呢? 貌似不行吧?

所以接下来,我们来实现最后一个功能 取到返回结果

返回结果

我们思考一个问题 返回结果在哪呢?

用户传递一个函数给我们 返回一个新的函数

那么返回结果一定是在用户传递给我们的那个函数上的

所以关键就是 将用户的那个函数的返回结果传递出来

现在 我们这里有两个方案

  • 回调函数

  • Promise

我们先来看下回调函数的版本

//回调函数版本functiondebounce(fn,delay,immediate=false,resultCallBack){lettimer=null;letisInvoke=false;letresult=null;const_debounce=function(...args){if(timer)clearTimeout(timer);if(immediate&&!isInvoke){//接收结果result=fn.apply(this,args);resultCallBack(result);isInvoke=true;}else{timer=setTimeout(()=>{//接收结果result=fn.apply(this,args);resultCallBack(result);isInvoke=false;},delay)}}_debounce.cancel=function(){if(timer)clearTimeout(timer);timer=null;isInvoke=false;}return_debounce;}

实际应用

const_debounce=()=>{debounce(test,1000)().then(res=>{console.log(res);})}input.oninput=_debounce;

回调函数的是不是比较简单? 我们来看下Promise版本的 在实际应用的时候要注意一些坑

functiondebounce(fn,delay,immediate=false){lettimer=null;letisInvoke=false;letresult=null;const_debounce=function(...args){//在返回的函数中直接整体返回一个Promsie对象//将结果传入resolve中returnnewPromise((resolve,rejected)=>{if(timer)clearTimeout(timer);if(immediate&&!isInvoke){result=fn.apply(this,args);resolve(result)isInvoke=true;}else{timer=setTimeout(()=>{result=fn.apply(this,args);resolve(result);isInvoke=false;},delay)}})}_debounce.cancel=function(){if(timer)clearTimeout(timer);timer=null;isInvoke=false;}return_debounce;}

实际调用

const_debounce=function(...args){debounce(test,1000).apply(this,args).then(res=>{console.log(res);})};input.oninput=_debounce;

注意到了吧 我们对原来的函数又封装了一层 因为只有这样才能拿到promise的结果

同时this和event不会出问题

看到这里的小伙伴们真棒,相信你们防抖函数一定没问题了,待会我们就开始讲解 节流函数该如何实现

节流函数的实现

节流函数我们也是从几个方面逐步实现,带着大家一步步的解开节流函数的面纱.

基本实现

大家可以想下,节流函数该如何实现.

一段时间内,只会触发一次操作,后续的操作就不会被触发.

我们可以拿到当前的时间戳 来进行计算

我们直接通过代码来讲吧 比较方便讲

functionthrottle(fn,interval){letlastTime=0;const_throttle=function(){//首先拿到当前的时间constnowTime=newDate().getTime();//传递进来的时间间隔用当前的时间减去上一次触发的时间//得到最新的剩余时间constreamainTime=interval-(nowTime-lastTime);if(reamainTime<=0){fn();//如果剩余时间小于0说明已经达到一个间隔//并且将现在的时间赋值给lastTime//在时间间隔内这样无论执行多少次都只会执行第一次的操作//因为第一次的lastTime是0而nowTime是比较大的//减去之后一定是个负数所以会执行第一次//而不会执行后续的操作lastTime=nowTime;}}return_throttle;}

大家看下我上面这段代码 还是比较好理解的吧,面试的话能够写出这一部分已经很可以了,但是要想更加出彩,能和面试官多唠会的吧,我们接着看下面的实现

leading实现

我们在基本实现中,其实已经将这个功能已经实现了,但是并不是可以控制的,我们这个实现是将是否首次触发交给用户来决定,大家可以想下该如何实现

基本实现中,我们是如何实现第一次触发的?

是不是通过拿到的时间戳非常大,而lastTime为0所导致的呢?

所以我们是不是可以让lastTime也能拿到当前的时间戳呢,这样子, nowTime和lastTime相减的时候,是不是就不会变成负数呢?

代码实现

//考虑到我们后面会有很多功能要实现//所以我们使用选项来进行配置.避免造成更多参数functionthrottle(fn,interval,option={leading:true}){letlastTime=0;const{leading}=option;const_throttle=function(){constnowTime=newDate().getTime();//在leading和lastTime为false的情况下//就将nowTime赋值给lastTime,这样就不会在第一次就执行操作了if(!leading&&!lastTime)lastTime=nowTime;constreamainTime=interval-(nowTime-lastTime);if(reamainTime<=0){fn();lastTime=nowTime;}}return_throttle;}

大家是不是理解了呢? 我个人认为还是比较好懂的吧,不懂的可以在评论区留言,我看到就会给大家解答的

接下来,我们看下和这个情况相反的一种状况,如果我们想要在最后一次操作的时候进行一次触发操作的话,该如何去做呢?

trailing实现

这一块是比较难的部分了,会有点难,大家不懂的话,要多看几遍,实在有不明白的,欢迎评论区留言

首先最后一次触发操作时,我们该怎么样让它执行?

我提供一个思路,当我们最后一次触发操作的时候,拿到距离间隔还有多少时间结束,加上一个定时器,让他根据这个剩余时间去按时执行

代码实现

functionthrottle(fn,interval,option={leading:true,tralling:false}){letlastTime=0;lettimer=null;const{leading,tralling}=option;const_throttle=function(...args){constnowTime=newDate().getTime();if(!leading&&!lastTime)lastTime=nowTime;constreamainTime=interval-(nowTime-lastTime);if(reamainTime<=0){fn.apply(this,args);lastTime=nowTime;if(timer){clearTimeout(timer)timer=null;}//如果执行了这一部分那么后面的tralling就没有必要去执行//说明刚好执行到了这一步后面的最后按下就不需要return;}if(tralling&&!timer){timer=setTimeout(()=>{timer=null;/**`*首先按下第一次的时候这个定时器已经被加上了*每次进来的时候等待一定时间定时器会被置空方便下次使用*根据剩余时间来判断执行*如果leading为falselastTime会被设置为0会在规定的剩余时间到达后去执行这个函数而remianTime那个部分就不会被执行因为remainTime会一直保持在一个正数状态*如果leading为truelastTime会被设置为当前的时间这样在下一次的操作下,remainTime才会发生变化**/lastTime=!leading?0:newDate().getTime();fn.apply(this,args);},reamainTime)}}return_throttle;}

是不是比较难懂呢? 我在来解释一下啊

首先如果remainTime已经小于0了,那么fn就会去执行,我们也就不需要去执行后续的操作了 会直接返回

那么如果remainTime没有小于0,我们会设置定时器,在定时器内部,我们需要先把timer清空,防止下一次触发的时候又触发了.

其次,我们要将lastTime进行一个处理

如果我们之前设置的leading是false的话,那么我们需要将lastTime置为0,这样在下一次的触发操作的时候,才能触发leading为false的情况下的逻辑语句

leading为true的情况下,需要将lastTime设置为当前的时间戳,这样在下一次的操作的时候,才会remainTime才会发生变化,逻辑才能执行下去.

大家有没有听明白呢? 可能是会有点难懂,但是好好多看几遍,还是能够理解的我相信!!!

接下来的操作就比较简单了,大家可以安心食用,和防抖函数一样,是取消功能和返回结果

取消功能和返回结果

因为这个和防抖函数是一样的,所以我这里直接就放代码了

functionthrottle(fn,interval,option={leading:true,tralling:false,resultCallback}){letlastTime=0;lettimer=null;letresult=null;const{leading,tralling,resultCallback}=option;//两种结果回调//和防抖函数是一样的//1.通过传递一个回调函数//2.通过promise进行结果回调const_throttle=function(...args){returnnewPromise((resolve,reject)=>{constnowTime=newDate().getTime();if(!leading&&!lastTime)lastTime=nowTime;constreamainTime=interval-(nowTime-lastTime);if(reamainTime<=0){result=fn.apply(this,args);resultCallback(result);resolve(result);lastTime=nowTime;if(timer){clearTimeout(timer)timer=null;}return;}if(tralling&&!timer){timer=setTimeout(()=>{timer=null;lastTime=!leading?0:newDate().getTime();result=fn.apply(this,args);resultCallback(result);resolve(result);},reamainTime)}})}//取消功能_throttle.cancel=function(){if(timer)clearTimeout(timer);timer=null;lastTime=0;}return_throttle;}
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Spirit防抖函数underscore和节流函数lodash怎么用的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:SpringBoot2数据库实例分析下一篇:

8 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18