[查遗补漏] 防抖、节流

基本概念

  1. 防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

  2. 节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。固定间隔时间去执行函数

分别适合什么场景?

  • 节流:窗口的resize、 scroll
  • 防抖:输入框input的内容校验

手写节流函数:函数节流主要有两种实现方法:时间戳和定时器

1. 时间戳写法:

当频繁触发事件时,第一次立即执行,而后再怎么频繁触发事件,也都是delay时间才执行一次。而当最后一次事件触发完毕后,事件不再被执行(最后一次触发事件与倒数第二次触发事件的间隔小于delay)

function throttle(fn, delay){
    let last = 0;
    
    return function(){
        let now = Date.now();
        
        if(now - last >= delay){
            last = now;
            fn.apply(this, arguments);
        }
    }
}

function handle(){
    console.log(Math.random());//打印随机数
}

const throttleHandle = throttle(handle, 1000);
throttleHandle();
throttleHandle();
throttleHandle();
throttleHandle();//频繁调用
复制代码

2. 定时器写法:

当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样可以设置下一个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行,而后再怎么频繁触发事件,也都是delay时间才执行。最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。

function throttle(fn, delay){
    let timer = null;
    
    return function(){
        let context = this;
        let args = arguments;
        if(!timer){
            timer = setTimeout(function(){
                fn.apply(context, args);
                timer = null;
            },delay);
        }
    }
}
复制代码

3. 时间戳+定时器:

在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。

 function throttle(fn, delay){
    let timer = null;
    let startTime = Date.now();
    
    return function(){
        let curTime = Date.now();
        //curTime - startTime 本次间隔已经过去多久
        //剩余时间 = 完整间隔时间 - 本次间隔剩余时间
        let remainning = delay - (curTime - startTime);
        let context = this;
        let args = arguments;
        clearTimeout(timer);
        if(remainning <= 0){
            fn.apply(context, args);
            startTime = null;
        }else{
            timer = setTimeout(fn, remainning);
        }
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享