函数防抖与节流

稳住,不许抖!

Posted by Niro on January 4, 2019

函数防抖(debounce)

防抖动是将多次执行变为最后一次执行。

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

打开控制台查看:

没有防抖的输入:


有防抖的输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 *
 * @param fun {Function}   实际要执行的函数
 * @param delay {Number}  延迟时间,单位是毫秒(ms)
 *
 * @return {Function}     返回一个“防反跳”了的函数
 */
function ajax(content) {
  console.log('刚刚输入的内容:' + content)
}
//无防抖
let inputA = document.getElementById('unDebounce')
inputA.addEventListener('keyup', function (e) {
    ajax(e.target.value)
})
// 防抖
function debounce(fun, delay) {
  // args 就是 e.target.value
  return function (args) {
    let that = this;
    // 清除上一次防抖的计时器
    clearTimeout(fun.id);
    fun.id = setTimeout(function () {
      fun.call(that, args);
    }, delay);
  }
}
let inputB = document.getElementById('debounce');
let debounceAjax = debounce(ajax, 500);
inputB.addEventListener('keyup', function (e) {
  debounceAjax(e.target.value);
})

可用箭头函数简化代码:

1
2
3
4
5
6
7
8
9
10
11
// 防抖
function debounce(fun, delay) {
  // args 就是 e.target.value
  return function (args) {
    // 清除上一次防抖的计时器
    clearTimeout(fun.id);
    fun.id = setTimeout(() => {
      fun(args);
    }, delay);
  }
}

可见在加入了防抖以后,当你在频繁的输入时,并不会发送请求,只有当你在指定间隔内没有输入时,才会执行函数。像是LOL中的回城技能,只有等待蓝条满了才会真正触发回城。

函数节流(throttle)

将多次执行变成每隔一段时间执行

规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

有节流的输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
*
* @param fun {Function}   实际要执行的函数
* @param delay {Number}  执行间隔,单位是毫秒(ms)
*
* @return {Function}     返回一个“节流”函数
*/
function throttle(fun, delay) {
  // 记录上次执行的时间
  let last;
  // 定时器
  let deferTimer;
  // 返回的函数,每过 delay 毫秒就执行一次 fn 函数
  return function() {
    // 保存函数调用时的上下文和参数,传递给 fn
    let that = this;
    let _args = arguments;
    let now = +new Date();
    // 如果距离上次执行 fn 函数的时间小于 delay,那么就放弃执行 fn,并重新计时
    if (last && now < last + delay) {
      clearTimeout(deferTimer);
      // 保证在当前时间区间结束后,再执行一次 fn
      deferTimer = setTimeout(function() {
        last = now;
        fun.apply(that, _args);
      }, delay);
    } else {
      // 在时间区间的最开始和到达指定间隔的时候执行一次 fn
      last = now;
      fun.apply(that, _args);
    }
  };
}
let throttleAjax = throttle(ajax, 1000);
let inputC = document.getElementById("throttle");
inputC.addEventListener("keyup", function(e) {
  throttleAjax(e.target.value);
});

参考

debounce - github