03月20, 2017

浅谈debounce和throttle

debouncethrottle是老生常谈的处理频繁触发函数的两种不同的方式。网上讲它们两者之间的区别的文章已经比比兼是,但很多都是说怎么用lodashunderscore中这两个方法,当然也有部分讲它们内部是如何实现的。本文是我自己查看lodashunderscore的源码加上自己的理解做的一个总结。

debounce

debounce这个英文单词的意思是“去抖”。它的作用是让连续触发的回调函数只调用一次。最简单的实现方式如下:

function debounce(fn, timeout){
    var timer = null;
    return function(){
        if(timer){
            clearTimeout(timer);
        }
        timer = setTimeout(function(){
            fn();
        }, timeout)
    }
}

从上面的代码中我们可以看到,首先定义了一个变量timer用于存储当前的定时器对象,函数在接连触发的过程中,如果timer不为空,则清除之前的定时器并重新添加。这样,只有最后一个定时器被保留并执行。

它的用法也很简单:

document.getElementById('#input').addEventListener('keyup', debounce(function(){
    console.log('keyup');
}, 500));

它的一个用途是对用户输入的内容与服务端交互进行时,只在最后用户停止输入时发送请求。

throttle

throttle这个英文单词的意思是“节流”。它的作用是让连续触发的回调函数间隔一定的时间执行一次。

通常我们有两种实现方式,第一种是首先定义变量lastCallTime来记录回调上一次调用的时间,然后用当前时间减去上次调用的时间与timeout作比较。代码如下:

function throttle(fn, timeout){
    var lastCallTime = 0;
    return function(){
        var time = Date.now();
        if(time - lastCallTime >= timeout){
            fn();
            lastCallTime = time;
        }
    }
}

另一种方式依然是利用定时器,如果定时器不是null则直接返回,如果定时器为null,则通过setTimeout设置回调,并在毁掉中讲定时器对象timer置为null。代码如下:

function throttle(fn, timeout){
    var timer = null;
    return function(){
        if(timer){
            return;
        }
        timer = setTimeout(function(){
            fn();
            timer = null;
        }, timeout)
    }
}

这两种方式的使用方法一样,如下:

window.addEventListener('resize', throttle(function(){
    console.log('resize');
}, 500));

我们在改变浏览器窗口大小的过程中,会每隔500ms打印一次“resize”。

补充

既然实现方式这么简单,我们何必要引入lodashunderscore等函数库呢?

仔细想想throttle的两种实现方式,他们的最终效果一样吗?答案肯定是不一样的。

假设我们设置timeout为500。我们拖动浏览器窗口2200ms,如果使用第一种实现,在第一次触发resize时我们就会打印resize,也就是分别在拖动的第0ms、500ms、1000ms、1500ms、2000ms(实际上不会这么精确)打印resize

而使用第二种方式实现,我们将分别在拖动的第500ms、1000ms、1500ms、2000ms、2500ms(同样不会这么精确)打印resize

lodashunderscore都提供了参数供我们选择触发的第一次是否执行以及触发停止后且定时器还存在的那一次是否继续执行。 下一章篇文章,我带领大家分析一下lodashunderscore分别都是如何实现这两个函数的。

本文链接:https://www.imliutao.com/post/debounce-throttle.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。