JS的防抖和节流

在浏览器中如果一个事件被频繁触发,比如输入框的 keyup, 窗口的 resize 以及 scroll 事件等,如果不做任何处理,事件的回调函数将会对应执行,这必然会加重浏览器的负担,影响用户的体验。面对这种场景,我们可以用函数的防抖 (debounce) 和节流 (throttle) 来处理。

函数防抖

防抖 debounce: 让事件触发时的回调在一定的延时后执行。如果在计时期间又触发了事件,则重新开始计时。

比如在做一个检索的输入框,输入的内容发送给后台查询。如果不做防抖处理我们来看下:

<input type="text" id="input">
复制代码

用打印来模拟请求处理:

var ipt = document.getElementById('input');
ipt.addEventListener('keyup', function(e){
  console.log(e.target.value);
});
复制代码

结果如下:

可见,每次触发事件都会执行回调函数,现在加入防抖处理:


var debounce = function(func, delay) {
  var timer = null
  return function() {
      var that = this;
      var args = arguments;
      
      if(timer) {
          clearTimeout(timer);
      }

      timer = setTimeout(function() {
          func.apply(that, args);
      }, delay)
  }
}

ipt.addEventListener('keyup', debounce(function(e){
  console.log(e.target.value);
}, 400))
复制代码

效果如下:

可见,输入框在停止输入400ms后执行回调。在防抖后的回调函数用 timer 记录计时,每次执行回调的时候会先清空之前的计时。注意这里的timer是闭包变量,始终保持着上一个计时。

函数节流

节流throttle: 让事件的回调一定时间间隔只执行一次。节流函数有两种实现方式,一种是记录增量,一种是定时方式。

用增量的方式实现节流:

var throttle = function(func, delay) {
    var pre = Date.now();
    return function() {
        var that = this;
        var args = arguments;
        var now = Date.now();

        if (now - pre >= delay) {
            func.apply(that, args);
            pre = now;
        }
    }
}

ipt.addEventListener('keyup', throttle(function(e){
    console.log(e.target.value);
}, 1000))
复制代码

节流的效果如下:

可见,无论怎么输入,事件回调总会在1s内执行一次。而且第一次输入会马上执行,这是因为处理节流的时候和第一次触发的时间间隔大于1s。但是最后一次触发不会执行回调。

利用计时方式处理节流:

var throttle = function(func, delay) {
    var timer = null;
    return function() {
        var that = this;
        var args = arguments;

        if(!timer) {
            timer = setTimeout(function() {
                func.apply(that, args);
                timer = null;
            }, delay)
        }
    }
}
复制代码

利用变量 timer 记录定时器,如果定时器存在,则不执行回调。否则创建一个延时器执行回调。这种方法和时间戳增量的区别就是第一个触发不会立即执行回调,但是最后一次时间会在延时后触发回调函数。

如果想要立即触发并且最后一次也要执行回调,可以利用时间戳和计时方式结合在实现节流:

var throttle = function(func, delay) {
    var timer = null;
    var pre = Date.now();
    return function() {
        var now = Date.now();
        var that = this;
        var args = arguments;
        var remain = delay - (now - pre);

        clearTimeout(timer);
        if (remain <= 0) {
            func.apply(that, args);
            pre = now
        }else {
            timer = setTimeout(function() {
                func.apply(that, args);
                pre = now;
            }, remain)
        }
    }
}
复制代码

上面的节流函数会先判断剩余的间隔时间,如果剩余时间小于0,则立即执行。否则创建一个剩余时间的定时。注意,每次要记得清空之前的定时。

应用场景

防抖 debounce 一般用来在输入检索,节约请求的资源。还有窗口的 resize,让不断调节窗口大小的最后一次触发。

节流 throttle 一般用在鼠标不断点击,让点击的回调按间隔执行一次。还有滑动 scroll 事件, 比如滚动到底部查询,按间隔请求一次数据来显示。

参考文章

juejin.im/post/5b8de8…

mp.weixin.qq.com/s/Vkshf-nED…

转载于:https://juejin.im/post/5c7a8640f265da2d8e71019e

你可能感兴趣的:(JS的防抖和节流)