防抖(debounce) 和 节流(throttling)

debounce的特点是当事件快速连续不断触发时,动作只会执行一次。

周期内有新事件触发,清除旧定时器,重置新定时器;这种方法,需要高频的创建定时器。

JavaScript 防抖 - Web前端工程师面试题讲解_哔哩哔哩_bilibiliJavaScript 防抖 - Web前端工程师面试题讲解https://www.bilibili.com/video/BV17b4y1X7yp/?spm_id_from=333.788

简单实现:

        <button id="btn" style="width: 100%;">按钮</button>

        const button = document.querySelector('button')
        function payMoney() {
            console.log('滴滴滴');
            console.log(this); // 不使用防抖函数this指向点击按钮
                               // 使用防抖函数this指向window
        }

        function debounce(fun,time) {
            let timer;
            return function() {
                let _this = this;
                let args = arguments
                clearTimeout(timer)
                timer = setTimeout(function() {
                    fun.apply(_this,args)
                },time)
            }
        }

        button.addEventListener('click',debounce(payMoney,1000))

        /* 
            function ebounce(func) {
                func()
            }
           难点1: 这样写的话,在定义监听函数的时候就直接执行了函数
           为了解决这个问题,使用高阶函数,在函数里面返回函数   
           function ebounce(func) {
                return function() {
                    func()
                }
            }   

            要进行延迟就相应的需要清除延时,为延时设置变量名,清除是使用 clearTimeout
            难点2: 清除以后在定义变量是会报错的    
            难点3: 1秒内多次执行,但是全部消息都陆续执行了
                  这里每次执行函数就是创建变量,清除延时,建立延时三个步骤;
                  而且每次点击的执行函数都是独立的,因为他们直接没有联系,
                  因此清除延时在这里完全不起作用;
                  要让他们直接有联系就需要利用作用域链了,也就是闭包;
                  把定义timer放到函数外
            难点4: this指向
            参数问题: js里函数没有设置参数是可以传入参数的
                    每一个执行函数有可能传入参数,而传入的参数是给payMoney函数使用的 

        */

封装一下:

        <button id="btn" style="width: 100%;">按钮</button>

        const button = document.querySelector('button')
        function payMoney() {
            console.log('滴滴滴');
            console.log(this); // 不使用防抖函数this指向点击按钮
                               // 使用防抖函数this指向window
        }

        function debounce(fun,wait) {
            let timer;
            let timerStamp;
            let _this;
            let args;
            let clear= () =>  {
                clearTimeout(timer)
            }
            let run = () => {
                timer = setTimeout(function() {
                    fun.apply(_this,args)
                },wait)
            }
            return function(){
                _this = this
                args = arguments
                let now = new Date().getTime()
                if(now-timerStamp < wait){
                    clear()
                }
                run()
                timerStamp = now
            }
        }

        button.addEventListener('click',debounce(payMoney,1000))

throttling,节流的策略是,固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。

throttling的特点在连续高频触发事件时,动作会被定期执行,响应平滑。

JavaScript 节流 - Web前端工程师面试题讲解_哔哩哔哩_bilibiliJavaScript 节流 - Web前端工程师面试题讲解https://www.bilibili.com/video/BV11Z4y1c7C9/?spm_id_from=333.788

小实验:

f       function coloring() {
            let r = Math.floor(Math.random() * 225);
            let g = Math.floor(Math.random() * 225);
            let b = Math.floor(Math.random() * 225);
            document.body.style.background = `rgb(${r},${g},${b})`
        }
        function throttle(fun,delay) {
            let timer;
            return function() {
                let _this = this;
                let args = arguments
                if(timer){
                    return
                }
                timer = setTimeout(function() {
                    fun.apply(_this,args)
                    timer = null
                },delay)
            }
        }
        window.addEventListener('resize',throttle(coloring,1000))
        
        /*
            判断触发的事件是否在时间间隔内,如果在时间间隔内,不触发事件,如果不在,就出发事件.
            如果timer被赋值,也就是任务在等待执行,暂时不改变timer的值,如果没有值,就直接赋值
            if timer有值,直接返回, 没有值,进行赋值
        */

第二种写法:

        function coloring() {
            let r = Math.floor(Math.random() * 225);
            let g = Math.floor(Math.random() * 225);
            let b = Math.floor(Math.random() * 225);
            document.body.style.background = `rgb(${r},${g},${b})`
        }
        function throttle(fun,delay) {
            let pre = 0;
            return function() {
                let _this = this;
                let args = arguments
                let now = new Date()
                if(now - pre > delay){  
                // 当前时间减去上一次执行的时间,如果大于传入的时间就执行,否则不执行
                    setTimeout(function() {
                        fun.apply(_this,args)
                        pre = now
                    })
                }
            }
        }
        window.addEventListener('resize',throttle(coloring,1000))

封装1:

         var throttle = (fn, wait) => {
                let timer;
                let context, args;
            
                let run = () => {
                    timer=setTimeout(()=>{
                        fn.apply(context,args);
                        clearTimeout(timer);
                        timer=null;
                    },wait);
                }
            
                return function () {
                    context=this;
                    args=arguments;
                    if(!timer){
                        console.log("throttle, set");
                        run();
                    }else{
                        console.log("throttle, ignore");
                    }
                }
            
            }
        window.addEventListener('resize',throttle(coloring,1000))

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值