防抖节流的实现与区分(详解带代码)

这是最近自己拍的一张照片,出去散心的时候给自己买了束花,是桔梗花,生活还是很美好的,记得给自己加点糖在这里插入图片描述
这是最近自己拍的一张照片,出去散心的时候给自己买了一束花,是桔梗花。这首纯音乐也很好听,推荐给伙伴们~——Tidal Wave 海浪

学过的东西真的要勤复盘才行,温故而知新,才能印在脑子里。这不,之前学的忘了,重新去查资料复习的时候发现真一个人一种理解,还有那种极为官方的定义解释真的大佬。所以,还是自己来篇笔记吧,也希望能对大家有帮助。
温馨提示:一定要自己理解,别怕花时间,文最后会写小总结。
没啥好怕的,真的不难,就是需要捋顺,听我细细说来。

防抖动(debounce)

非立即执行防抖&立即执行防抖

都是等待时间间隔后去返回事件函数结果,等待间隔时触发就重新定时,区别就是一个立即返回结果,一个拖延返回。
事件触发会执行你所定义的事件函数,但某些事件被频繁的触发然后频繁执行方法这是没必要的,防抖其实就是为了去控制触发频率。非立即执行,我认为这个非可以表示取反,直接跟立即执行是相反操作,立即执行就是触发事件后立即就去执行你定义的操作,非立即执行就是等待你限制的时间后再执行操作。

非立即执行

先等待设定时间,然后才执行事件方法,间隔时间内触发的事件不作数且会重置定时,度过完整时间间隔,才会去执行方法。
举个栗子,写个取输入框值的

我是输入框:<input type="text" id = "input1">
    <script>
      var text = document.getElementById('input1');
         function SendData() { 
            console.log(text.value)          
         }

         text.addEventListener('keyup' , debounce(SendData, 3000));
            
         function debounce(fn , delay) {
            var timer = null;  //创建个定时器(标准设置就初始化为null,为了能清除内存占用)
            return function() {
                clearTimeout(timer);  //重新定时,清除时间
                var context  = this;  
                var args = arguments; 
                timer = setTimeout(() => {
                     fn.apply(context , args);   
                     //将执行方法绑定到这里执行
                }, delay);
            }
         }
         </script>

了解或在此之前看过防抖的,指定发现这几行代码,基本上是固定要写的:

 var timer = null;    //清缓存
 clearTimeout(timer);  //清时间
 var context  = this;  //存个指向
 var args = arguments;  //收个参
立即执行

立即执行就是第一次立即返回事件函数结果,再次执行触发函数需等待间隔,间隔时间内若是频繁触发会重新定时(clearTimeout(timer)),间隔过后了可返回事件触发结果。

模拟个验证码发送:

   <button id = "btn">  点击发送验证码 </button>
    <script>
      var eat = document.getElementById('btn');
         function SendData() {
           console.log("XXXXXXXXX");           
         }
       
         eat.onclick = debounce1(SendData, 8000)   //delay时间内点击会重复调用,定时器会产生编号,一直按一直有
         function debounce1(fn , delayTime) {
              var timer = null; //清定时器
              return function() { 
                   //console.log(timer)  //如果你想不通timer到底是什么,你可以试着看看timer的输出
                   //clearTimeout(timer);  //取消定时器 (这里注掉了,表示是否在频繁触发后还重新计时,发验证码不能人家点你就重定时啊)
                   var context = this;
                   var args = arguments;
                   console.log(timer);
                   var callTimer = !timer;  //最开始的时候timer一定是空,所以最开始必定执行一次                
                   if(callTimer) {                          
                        fn.apply(context , args);
                        console.log('验证码已发送~')  
                   }else{
                        console.log('您操作的太频繁啦!请耐心等待哟~');
                   }
                    timer = setTimeout(() => {
                      timer = null;
                   },delayTime); 
                }
             }

    </script>

要清楚流程,宏任务是异步的,先执行同步代码,delayTime后将timer设成null
timer为null ,callTimer才能为真,为真才能触发函数(也就是过了8s)。
delay时间内点击,会执行回调,就又触发了一个timer++,所以timer就为真了。

到这里如果你还是对防抖的定义似懂非懂,看下我编的这段话,希望对你有帮助:

可把频繁触发事件比喻成抖动(抖阿抖抖啊抖)
因为有些事件被触发的频率高,我们还要让它执行方法去干活,就抖起来了,但是总抖不好,就像抖腿似的跟个缝纫机似的它也累挺啊,别让它抖起来,我们就可以把它优化,让它不用那么频繁的取值,稳重一点,间隔取值~ (在设定的间隔时间后再取)

防抖函数可能更基于设定时间限制,防止频繁处理事件函数。

立即执行与非立即执行的结合版本

到这里你可以在脑海里缕下立即与非立即防抖的实现及区别。
两个的结合说白了就是传参控制它是立即执行还是让它非立即。
上代码!

  我是立即执行:<input id="execNow" type="text"/>
    我是非立即执行:<input id="exec" type="text"/>
    <script>
       //立即执行获取
         var execNow = document.getElementById('execNow');
         function ExecNow() {
            console.log('立即执行获取' + execNow.value)
         }
         execNow.onkeyup = debounce1(ExecNow, 5000 , true); 


         //非立即执行获取
         var exec = document.getElementById('exec');
         function Exec() {
            console.log('非立即执行获取' + exec.value)
         }
         exec.onkeyup = debounce1(Exec, 3000 , false); 
        //防抖
         function debounce1(fn , delayTime , flag) {
              var timer = null;
              return function() {   
                     clearTimeout(timer);   
                     var context = this;
                     var args = arguments;  
                     var callNow = !timer;   
                     if(flag) {         //立即还是非立即的判断 , flag为真就是立即
                        if(callNow) {  //进入立即执行防抖函数
                            fn.apply(context, args); //立即执行一次
                        } else {
                           console.log("wait time");
                        }
                        timer = setTimeout(() => { 
                            timer = null;   //delay后清缓存    
                            console.log(timer);
                           }, delayTime);       
                     //非立即防抖
                     }else {   
                              timer = setTimeout(() => {
                              fn.apply(context , args);
                           }, delayTime);                                               
                     }
                }
            }
节流

节流,即便频繁的触发事件,也只会在拖延时间只后执行一次事件函数,间隔触发的会被忽略。无论怎么点,都只会在时间间隔后执行。
节流更适合去做可能被频繁打扰的工作,他足够专心。
(减少来势汹汹的触发流,比如滚轮事件)
举例获取滚轮每次滑动的距离:

  <div id = "div1" style="width:500px;height:200px;overflow: scroll;">
         莎士比亚十四行诗12<br/>
          辜正坤译<br/>
          当我数着壁上报时的自鸣钟,<br/>
          见明媚的白昼坠入狰狞的夜,<br/>
          当我凝望着紫罗兰老了春容,<br/>
          青丝的卷发遍洒着皑皑白雪;<br/>
          当我看见参天的树枝叶尽脱,<br/>
          它不久前曾荫蔽喘息的牛羊;<br/>
          夏天的青翠一束一束地就缚,<br/>
          带着坚挺的白须被舁上殓床;<br/>
          于是我不禁为你的朱颜焦虑:<br/>
          终有天你要加入时光的废堆,<br/>
          既然美和芳菲都把自己抛弃,<br/>
          眼看着别人生长自己却枯萎;<br/>
          没什么抵挡得住时光的毒手 ,<br/>
          除了生育,当他来要把你拘走。<br/>
    </div>
    <script>
        var text = document.getElementById('div1');
        div1.addEventListener('scroll' ,throttle(exam, 2000));        
        function exam() {   
            console.log(text.scrollTop);
        }
            // 定时器方案
            function throttle(fn,delay){
                var timer = null;
                return function(){
                    var context = this;
                    var args = arguments;
                    if(!timer) {        // timer!== null执行
                        timer = setTimeout(function(){
                            fn.apply(context,args);
                            timer = null;
                        },delay)  // delay后执行函数,给定时器赋个空值null
                    }
                }
            }
    </script>

节流前,就滚动一下,给大家看下console:
在这里插入图片描述
节流后,滚动一下。
在这里插入图片描述

来说说区分吧

个人理解,防抖和节流在有些时候是可以混用的,并不是一点儿都不同,都是对事件进行触发频率的控制,就比如表单信息校验,输入信息时对信息格式进行检查,这个可以用非立即防抖,也可以用节流,我们可以根据是否在频繁触发时重新定时时间间隔来对防抖和节流的功能做区分,还有根据事件触发频率高低进行适宜性的选择,对于极频繁会被触发的事件使用节流控制,一般控制某控件事件发生就可以用防抖,不断频繁事件触发事件的时候是重定时还是继续等待时间,尽量根据需求区分来各司其职。而需要触发时就立即执行操作的就用立即执行防抖,若使用时无需清除定时就不写清除定时语句,是很灵活的。

PS:本文是原创文,是我自己在学习中做的总结,所以可能会有不正之处,欢迎指出,如果也能帮助到大家理解这部分知识那就再好不过了~欢迎留言
肝文不易,留个赞吧!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值