JS手写防抖与节流

1.概念:

防抖:指定内只执行一次,如果指定时间内再次被触发,则重新开始计时。实现主要需要利用闭包,定时器,arguments和this指向,立即执行。

节流:隔一段时间执行一次,如果指定时间内再次被触发,则不执行,指定时间后才继续执行。实现主要需要利用闭包,定时器(隔一段时间执行一次)/时间戳(立即执行),arguments和this指向。

2.防抖

简单版:

function debounce(func, wait){
    let timerId = null;
    return function(){
        let _This = this,
            args = arguments;
         if(timerId) clearTimeout(timerId);
         timerId = setTimeout(function(){
            func.apply(_This,args);
            },wait);
    }
}

立即执行:

document.addEventListener('mousemove', _.debounce(handleMouseMove, 60));
function debounce(func, wait, immadiate){
    let timerId = null;
    return function(){
       let _This = this,
           args = arguments;
        if(timerId) clearTimeout(timerId);

        if(immadiate){
            //callNow也可表示第一次执行,第一次是true,会重新设置定时器,且func.apply(_This, args),后续为false且在指定时间内重新创建定时器,直到指定时间结束
            let callNow = !timerId;
            timerId = setTimeout(function(){
               timerId = null;
            },wait);
            if(callNow) func.apply(_This,args);
        }else{
            timerId = setTimeout(function(){
                func.apply(_This,args);
            },wait);
        }
    }
}

3.节流

时间戳方式:

立即执行,停止触发后不会最后再执行一次

function throttle(func, wait) {
    let lastCallTime = Date.now(); //也可以用new Date().valueof()

    return function() {
        let _This = this,
            args = arguments,
            curCallTime = Date.now();
        //只在时间到了以后,重新执行函数且重新计时
        if (curCallTime - lastCallTime >= wait) {
            func.apply(_This, args);
            lastCallTime = Date.now();
        }
    }
}

定时器方式:

不立即执行,隔段时间执行一次

function throttle(func, wait){
    let timerId = null;
    return function(){
        let _This = this,
            args = arguments;
        if(!timerId){
            timerId = setTimeout(function(){
                func.apply(_This,args);
                timerId = null;
            },wait);
        }
    }
}

时间戳和定时器结合方式:

同时利用时间戳立即执行和定时器可以隔段时间执行的优点

function throttle(func, wait){
    let lastCallTime = Date.now();
    let timerId = null;
    return function(){
        let _This = this,
            args = arguments,
            curCallTime = Date.now();
        
        if(curCallTime- lastCallTime >= wait){
            if(timerId) clearTimeout(timerId);
            func.apply(_This,args);
            lastCallTime = Date.now();
        }
        if(!timerId){
            lastCallTime = Date.now();
            timerId = setTimeout(function(){
            func.apply(_This,args);
                timerId = null;
            },wait);
        } 
    }
}

第三个参数设置第一次或最后一次是否执行:

/**
 * 将时间戳和定时器结合
 * @param {*} func 
 * @param {*} wait 
 * @param {*} options (leading:第一次是否执行  trailing:离开时是否执行 ) 
 * @returns 
 */
function throttle(func, wait, options) {
    let _This, args, timer;
    let lastCallTime = Date.now();
    //如果没有设置第三个参数,那么第三个参数为空对象
    if (!options) options = {};

    return function() {
        _This = this;
        //获取当前函数的实参
        args = arguments;
        //获得时间戳
        let curTime = Date.now();

        if (options.leading === false && !lastCallTime) {
            lastCallTime = curTime;
        }

        //在首次进入的时候,能够保证立即执行。
        if (curTime - lastCallTime > wait) {
            if (timer) clearTimeout(timer);
            func.apply(_This, args);
            lastCallTime = curTime;
        };
        //在后续的执行过程中完成每wait时间内,执行一次。
        if (!timer && options.trailing !== false) {
            timer = setTimeout(function() {
                lastCallTime = Date.now();
                func.apply(_This, args);
                timer = null;
            }, wait)
        }
    };
}
document.addEventListener('mousemove', _.throttle(handleMouseMove, 1000, {
    leading: true,
    trailing: true
}));

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值