js的节流和防抖

239 阅读3分钟

一.概念:

函数防抖(debounce): 触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。

函数节流(throttle): 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。

二.实现方式

防抖函数实现: 每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法。

缺点: 如果事件在规定事件内间隔被不断触发,则调用方法会不断的延迟。

代码:

//实现一:
function debounce(fn,delay){
    var timeout = null; //创建一个标记来存放定时器的返回值
    return function(e){
        //每当用户输入的时候把前一个setTimeout clear掉
        clearTimeout(timeout);
        //然后创建一个新的setTimeout,这样就能保证interval 间隔内如果事件持续触发,就不会执行fn函数
        timeout = setTimeout(()=>{
            fn.apply(this,arguments);
        },delay);
    };
}

//实现二:
function debounce(fn,wait){
    var timeout = null;
    return function(){
        if(timeout !== null){
            clearTimeout(timeout);
        }
        timeout = setTimeout(fn,wait);
    }
}

//处理函数
function handle(){
    console.log(Math.random());
}

//滚动事件
window.addEventListener('scroll',debounce(handle,1000))

节流函数实现: 每次触发事件时,如果当前有等待执行的延时函数,则直接return

代码:

//时间戳
function throttle(fn,delay){
    var pre = Date.now();
    return function(){
        var content = this;
        var args = arguments;
        var now = Date.now();
        if(now - pre >= delay){
            fn.apply(content,args);
            pre = Date.now();
        }
    }
}
//定时器
function throttle(fn,delay){
    var timer = null;
    return function(){
        var content = this;
        var args = arguments;
        if(!timer){
            timer = setTimeout(()=>{
                fn.appply(content,args);
                timer = null;
            },delay)
        }
    }
}
//实现三
function throttle(fn,delay){
    let valid = true; //通过必包保存一个标记
    return function(){
        //在函数开头判断标记是否为true,不为true则return
        if(!valid){
            return false
        }
        //立即设置为false
        valid = false
        //将外部传入的函数的执行放在setTimeout中
        setTimeout(()=> {
            //最后在setTimeout执行完毕后把标记设置为true,表示可以执行洗一次循环了
            //当定时器没有执行的时候标记永远是false,在开头被return掉
            fn.apply(this,arguments);
            valid = true
        }.delay)
    }
}

//处理函数
function handle(){
    console.log(Math.random());
}

//滚动事件
window.addEventListener('scroll',throttle(handel,1000));

总结:

函数防抖: 将几次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样依赖,只有最后一次操作能被触发。

函数节流: 使得一定时间内只触发一次函数。原理是通过判断是否达到一定时间来触发函数。

区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而防抖函数只是在最后一次事件后才触发一次函数。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段事件发一次Ajax请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景就适合用节流技术。

使用场景举例:

1.搜索input事件,例如要支持输入实时搜索可以使用节流方案

2.页面resize事件,常见于做页面适配。需要根据最终呈现的页面情况进donm渲染,这种情形一般使用防抖,因为只需要判断最后一次的变化情况。

实际举例:

需求: vue 函数input输入值即请求,优化为用户输入完成之后再请求(函数防抖)

<el-input v-model="selectName" placeholder="请输入姓名查找"></el-input>
data(){
    return {
        selectName:null,
        timeout:null
    }
}

watch:{
    selectName(curVal,oldVal){
        //实现input连续输入,只发一次请求
        clearTimeout(this.timeout)
        this.timeout = setTimeout(()=>{
            this.handelChangeName(curVal)
        },500)
    }
}

handelChangeName(value){
    if(value === ''){
        return false;
    }
    console.log(value)
}