js中的防抖与节流

193 阅读2分钟
防抖与节流形成过程

首先在介绍防抖与节流之前,我们要清楚为什么我们需要它们?

在前端有许多高频事件比如 onscroll oninput resize onkeyup keydown...,这样执行频率比较高,还比如有一些输入框联想查询,我们不需要一输就发送ajax,我们要等待输入稳定时在进行输入,这是我们想要的。。

scroll和resize行为也会导致页面不断的重新渲染,如果在绑定的回调函数中大量操作dom会导致出现页面卡顿。。

这些都需要我们进行优化,这时候防抖(throttle),节流(debounce)就出现了

函数节流(Throttle)

节流就是保证一段时间内,核心代码只执行一次 打个比方:水滴积攒到一定重量才会下落

简易节流函数
 <button id="btn">快速点击</button>

实现一秒内点击一次

 let btn = document.getElementById('btn');
    function throttle(func,wait){
        let previous = 0;
        return function(){
            let now = Date.now();
            if(now - previous > wait){
                func.apply(this,arguments);
                previous  = now;
            }
        }
    }
    function logger(){
     console('logger')
    }
    btn.addEventListener('click',throttle(logger,1000));

节流函数完整版
// 实现了 trailing 最后一次点出会触发事件,leading:第一次点击不生效
   let btn = document.getElementById('btn');
    function throttle(func,wait,options){
        // trailing 最后一次触发
        let args , context,previous = 0,timeout; //将参数,函数上下文进行保存
        let later = function (){
            previous = options.leading === false ? 0:Date.now();
            func.apply(context,args);
            args =context = null;
        }
        let throttled = function(){
           args = arguments;
           context = this;
           let now =  Date.now();
           if(!previous && options.leading === false) previous = now;
           let remain = wait -  (now - previous);
        
           if(remain <=0){ //第一次
           if(timeout){
               clearTimeout(timeout);
               timeout = null;
           }
            func.apply(context,args);
            previous = now;
           }else if(!timeout && options.trailing !== false){ //最后一次点出会触发事件
            timeout = setTimeout(later,remain);
           }
        }
        return throttled;
    }
    function logger(){
     console('logger')
    }
    //  leading:false :第一次点击不生效
    
    btn.addEventListener('click',throttle(logger,1000,{ leading:false }));
函数防抖(Debounce)

防抖就是一段时间结束后,才能触发一次,如果一段时间未结束再次触发,就会重新开始计算时间。 打个比方: 你在做电梯,门快要关了,突然有人准备上来。电梯门会重新打开,延迟了电梯门关闭时间,上来之后就重新关闭。

防抖函数
 function debouce(func,wait,immediate){
     let timeout;
     return function(){
         clearTimeout(timeout); //重新开始计时
         if(immediate){
             let collNow = !time;
             if(collNow) func.apply(this,arguments);
         }
         timeout  = setTimeout(()=>{
             func.apply(this,arguments);
         },wait)
     }
 } 
 function logger(){
     console('logger')
    }
    // 第三个参数表示首次先触发一下
 btn.addEventListener('click',debounce(logger,1000,true)