什么是Debounce


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/09/20/%E4%BB%80%E4%B9%88%E6%98%AFDebounce/

摘要

本文主要讲述了:

  1. 什么是 Debounce
  2. 模式
  3. 实现
  4. underscope 的实现

正文

什么是 Debounce

Debounce(防抖)是一种“当函数被连续调用时”防止“函数连续执行”的算法。

防抖函数被第一次调用时并不会立即执行,而是直接返回上一次调用的返回值。同时防抖函数将进入时长为t毫秒的等待期,等待期结束后,防抖函数将执行第一次调用。

等待期内,如果防抖函数被第二次调用,那么第一次调用的执行将被取消并直接返回上一次调用的返回值。同时等待期将从零开始计时,等待期结束后,防抖函数将执行第二次调用。

等待期内,如果防抖函数被第三次调用,那么第二次调用的执行将被取消并直接返回上一次调用的返回值。同时等待期将从零开始计时,等待期结束后,防抖函数将执行第三次调用。

等待期内,如果防抖函数被第i次调用,那么第i-1次调用的执行将被取消并直接返回上一次调用的返回值。同时等待期将从零开始计时,等待期结束后,防抖函数将执行第i次调用。

模式

前沿执行

防抖函数被第一次调用时,防抖函数将立即执行第一次调用。等到第一次调用执行完成后,防抖函数会进入时长为t毫秒的等待期。

等待期内,如果防抖函数被第二次调用,那么第二次调用将不会执行并直接返回上一次调用的返回值,同时等待期将从零开始计时。

等待期内,如果防抖函数被第三次调用,那么第三次调用将不会执行并直接返回上一次调用的返回值,同时等待期将从零开始计时。

等待期内,如果防抖函数被第i次调用,那么第i次调用将不会执行并直接返回上一次调用的返回值,同时等待期将从零开始计时。

实现

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
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
*
* @param {function} func - 原函数
* @param {number} wait - 延迟时间(单位:毫秒)
* @param {object} options - 选项
* @param {boolean} options.leading - 是否开启前沿执行模式
* @returns {function} 经过debounce处理的新函数
*/
function _debounce(func, wait, options) {
var lastCallTime;
var timer;
var result;

return function () {
var context = this;
var args = arguments;

// 判断是否为前沿执行模式
if (options && options.leading) {
// 前沿执行模式

// 获取本地时间
var now = Date.now();

if (!lastCallTime) {
// 第一次执行
result = func.apply(context, args);
} else if (lastCallTime + wait > now) {
// 等待期结束
result = func.apply(context, args);
}

// 等待期内将不会执行
lastCallTime = now;
} else {
// 后沿执行模式

// 等待期内,解除延时调用
if (timer) {
clearTimeout(timer);
timer = null;
}

// 等待期内,启动新的延时调用
timer = setTimeout(function () {
result = func.apply(context, args);
}, wait);
}
return result;
};
}

underscope 的实现

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
_.debounce = function (func, wait, immediate) {
/*
* timeout是计时器Id
* result是func()的返回值
*/
var timeout, result;

var later = function (context, args) {
// 将计时器Id置空
timeout = null;

/*
* 前沿模式下,不会传入参数,args为undefined
* 后沿模式下,立即执行func()并记录返回值
*/
if (args) result = func.apply(context, args);
};

// restArguments()是underscore中关于剩余参数的实现
var debounced = restArguments(function (args) {
// 如果在等待期内,解除延时调用
if (timeout) clearTimeout(timeout);

// 判断是否是前沿模式
if (immediate) {
// 前沿模式

/*
* 第一次执行时,callNow为true
* 等待期内,由于延时调用被解除,计时器Id还没有被置空,因此callNow为false
*/
var callNow = !timeout;

// 启动延时调用将计时器Id置空
timeout = setTimeout(later, wait);

/*
* 第一次执行时,立即执行func()并记录返回值
* 等待期内,由于callNow为false,不会执行func()
*/
if (callNow) result = func.apply(this, args);
} else {
// 后沿模式(默认)

// 在等待期内,原有的延时调用已被解除,启动新的延时调用
timeout = _.delay(later, wait, this, args);
}

return result;
});

debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
};

return debounced;
};

参考资料

本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/09/20/%E4%BB%80%E4%B9%88%E6%98%AFDebounce/


本文对你有帮助?请支持我


支付宝
微信