JavaScript 函数节流 throttle 和防抖 debounce

今天和别人聊到JavaScript函数的节流和防抖,发现自己对这两个的区别很是模糊,遂小小实践一下,在此记录,希望对需要的人有所帮助。

节流 - 频繁操作,间隔一定时间去做一件事

举例说明:假定时间间隔为 500ms,频繁不停的操作 2s,且每两次执行时间小于等于时间间隔 500ms,那么就会执行 4 次,也就是每隔 时间间隔 500ms 执行一次。

防抖 - 频繁操作,一定时间间隔内只执行最后一次操作

举例说明:假定时间间隔是 500ms,频繁不停的操作 5s,且每两次执行时间小于等于时间间隔 500ms,那么最后只执行了 1 次,也就是每一次执行时都结束了上一次的执行。

代码示例

    //节流方法 1
    function throttle1(method, duration){
        var prevTime = new Date();
        return function () {
            var context = this,
                currentTime = new Date(),
                resTime = currentTime - prevTime;
            //打印出本次调用方法和上次执行方法的时间差
            console.log("时间差"+resTime);
            //当本次调用距离上次执行方法的时间差大于等于要求时间间隔时,执行一次方法
            if(resTime >= duration){
                method.apply(context);
                //记录执行方法的时间
                prevTime = currentTime;
            }
        }
    }
    //节流方法 2
    function throttle2(method, duration){
        //当前时间间隔内是否有方法在执行(或者说方法的调用是否在进行)
        var runningFlag = false;
        return function (e) {
            // 判断当前是否有方法在执行,有,则什么都不做
            if (runningFlag) {
                return false;
            }
            //开始执行
            runningFlag = true;
            setTimeout(function(){
                method(e);
                //执行完毕,声明当前没有正在执行的方法,方便下一个时间间隔内的调用
                runningFlag = false;
            }, duration)
        }
    }
    //防抖
    function debounce(method, duration){
        var timer = null;
        return function(){
            var context = this,
                args = arguments;
            //在本次调用之前的一个间隔时间内,有方法在执行,则终止该方法的执行
            if(timer){
                clearTimeout(timer);
            }
            //开始执行本次调用
            timer = setTimeout(function(){
                method.apply(context, args);
            },duration);
        }
    }
    //模拟三个执行方法
    function jieliu1(){
        console.log("节流 1");
    }
    function jieliu2(){
        console.log("节流 2");
    }
    function fangdou(){
        console.log("防抖");
    }
    //持续执行时间
    var totalTime = 2000;

    var jieliuFn1 = throttle1(jieliu1,500);
    var jieliuFn2 = throttle2(jieliu2,500);
    var fangdouFn = debounce(fangdou,500);

    (function(duration){
        setInterval(function(){
            if( totalTime > 0 ){
                jieliuFn1();
                jieliuFn2();
                fangdouFn();
                totalTime -= duration;
            }
        },duration);
    })(100);

运行结果

时间差 100
时间差 201
时间差 303
时间差 401
时间差 504
节流 1
时间差 98
节流 2
时间差 199
时间差 300
时间差 396
时间差 496
时间差 597
节流 1
时间差 100
节流 2
时间差 203
时间差 299
时间差 402
时间差 500
节流 1
时间差 103
时间差 204
节流 2
时间差 303
时间差 400
节流 2
防抖

结论

由以上运行结果可以看出,节流1 出现了 3 次,节流2 出现了 4 次,防抖出现了 1 次。防抖实现顺利,但是两个节流方法的执行结果存在差异。
观察时间差可以看出,每次节流1 执行时,时间差并不会都是 500 整,也就是说,一共调用 2 秒时,节流1 并不能做到每隔 500 毫秒执行一次而共执行 4 次,第四次执行往往因为前面的 3 次执行的时间误差,而导致到达时间 2 秒时,最后一次的时间差无法达到 时间间隔 500ms 以上,以至于只能执行 3 次。

结论:当在一个大范围的时间内,比如两小时内,每几分钟执行一次,超过2小时则不再实行,推荐使用第一种节流方式,;如果仅仅要求间隔一定时间执行一次,推荐使用第二种节流方法;防止频繁操作,比如表单多次提交,推荐使用防抖。

如有问题,欢迎指正,谢谢!

你可能感兴趣的:(javascript)