2020-08-09-throttle-debounce

84 阅读2分钟

防抖节流原理、区别以及应用,请用js实现。

防抖

原理:在时间被触发n秒之后再执行回调,如果在这n秒内又被触发,则重新计时

适用场景:

  • 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
  • 搜索框联想场景:防止联想发送请求,只发送最后一次输入
//简易版实现
function debounce(func,wait){
    let timeout;
    return function(){
        const context=this;
        const args=arguments;
        clearTimeout(timeout);
        timeout=setTimeout(() => {
            func.apply(context,args);
        }, wait);
    }
}
//立即执行版实现:有时候希望立刻执行函数,然后等到停止触发n秒后,才可以重新执行。
function debound1(func,wait,immediate){
    let timeout;
    return function(){
        const context=this;
        const args=arguments;
        if(timeout) clearTimeout(timeout);
        if(immediate){
            const callNow=!timeout;
            timeout=setTimeout(() => {
                timeout=null;
            }, wait);
            if(callNow) func.apply(context,args);
        }else{
            timeout=setTimeout(() => {
                func.apply(context,args);
            }, wait);
        }
    }
}

//返回值版实现
//func函数可能会有返回值,所以需要返回函数结果,但是当immediate为false的时候,因为使用了setTimeout,我们将func.apply(context,args)的返回值赋给变量,最后在return的时候,值将会一直是undefined,所以只在immediate为true的时候返回函数的执行结果
function debounce2(func,wait,immediate){
    let timeout,result;
    return function(){
        const context=this;
        const args=arguments;
        if(timeout) clearTimeout(timeout);
        if(immediate){
            const callNow=!timeout;
            timeout=setTimeout(() => {
                timeout=null;
            }, wait)
            if (callNow) result=func.apply(context,args);
        }else{
            timeout=setTimeout(() => {
                func.apply(context,args);   
            }, wait);
        }
        return result;
    }
}
节流

节流的意思是,连续多次事件触发时, 会间隔触发

原理: 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

适用场景:

  • 拖拽场景:固定时间内只执行一次,防止高频次触发位置变动
  • 缩放场景:监控浏览器 resize
//使用时间戳实现:使用时间戳,当触发事件发生的时候,我们取出当前的时间戳,然后减去之前的时间戳(最开始设值为0),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前时间戳,如果小于,就不执行 

 function throttle(func,wait){
     let context,args;
     let previous=0;
     return function(){
         let now=+new Date();
         context=this;
         args=arguments;
         if(now-previous > wait){
             func.apply(context,args);
             previous=now
         }
     }
 }
//使用定时器实现:当触发事件的时候,我们设置一个定时器,在触发事件的时候,如果定时器存在,就不执行,知道定时器执行,然后执行函数,清空定时器,这样就可以设置下定时器
function throttle1(func,wait){
    let timeout;
    return function(){
        const context=this;
        const args=arguments;
        if(!timeout){
            timeout=setTimeout(() => {
                timeout=null;
                func.apply(context,args);
            }, wait);
        }
    }
}

//区别:节流不管事件触发多频繁保证在一定时间内一定会执行一次函数。防抖是只在最后一次事件触发后才会执行一次函数
// flag版本
const throttle2=(func,wait)=>{
    let flag=true;
    return function(...args){
        if(!flag) return;
        flag=flase;
        setTimeout(() => {
            func.apply(this,args)
            flag=true;
        }, wait);
    } 
}