throttle(节流)和debounce(去抖)

用来控制某个函数在一定时间内执行多少次的解决方案,两者相似而又不同

Posted by Liangyuqi on March 5, 2018
view times

一、throttle节流 vs debounce去抖

在开发过程中会遇到频率很高的事件或者连续的事件,如果不进行性能的优化,就可能会出现页面卡顿的现象,比如:

  1. 鼠标事件:mousemove(拖曳)/mouseover(划过)/mouseWheel(滚屏)
  2. 键盘事件:keypress(基于ajax的用户名唯一性校验)/keyup(文本输入检验、自动完成)/keydown(游戏中的射击)
  3. window的resize/scroll事件(DOM元素动态定位)

什么是debounce去抖

debounce的作用:当调用动作触发一段时间后,才会执行该动作,若在这段时间间隔内又调用此动作则将重新计算时间间隔

应用场景:

  • 提交ajax时,不希望1s中内大量的请求被重复发送
  • 对用户输入的验证,不在输入过程中就处理,停止输入后进行验证足以

实现思路:

  1. debounce函数会通过闭包维护一个timer
  2. 当同一action在delay的时间间隔内再次触发,则清理timer,然后重新设置timer

实现代码:

var debounce = function(action, delay) {
    var timer = null;
    
    return function() {
        var self = this, 
              args = arguments;
              
        clearTimeout(timer);
        timer = setTimeout(function() {
            action.apply(self, args)
        }, delay);
    }
}

function resizeHandler() {
    console.log("resize");
}

window.onresize = debounce(resizeHandler, 300);

什么是throttle节流

throttle跟debounce的最大不同就是,throttle会有一个阀值,当到达阀值的时候action必定会执行一次。

应用场景:

  • 对用户输入的验证,不想停止输入再进行验证,而是每n秒进行验证
  • 对于鼠标移动和窗口滚动,鼠标的移动和窗口的滚动会带来大量的事件,但是在一段时间内又必须看到页面的效果

实现代码:

var throttle = function(action, delay){
    var statTime = 0;
    
    return function() {
        var currTime = +new Date();
        
        if (currTime - statTime > delay) {
            action.apply(this, arguments);
            statTime = currTime ;
        }
    }
}    

function resizeHandler() {
    console.log("resize");
}

window.onresize = throttle(resizeHandler, 300);

总结

  • debounce:把触发非常频繁的事件合并成一次执行
  • throttle:设置一个阀值,在阀值内,把触发的事件合并成一次执行;当到达阀值,必定执行一次事件