函数节流(Throttle)和函数防抖(Debounce)是在业务开发中经常会用到的一种代码优化方式.它们可以节省计算资源,提升应用的性能和可靠性.

Throtter Function 和 Debounce Function 本质上一种高阶函数,在时间轴上控制函数调用频次.

Throttle

在一个单位时间内,函数只会被调用一次.即使这个单位时间函数被触发多次.

单位时间内 Throttle函数只会调用一次,则如果是连续触发Throttle函数,则两个Throttle函数调用时间差是固定的.

代码

1
2
3
4
5
6
7
8
9
10
11
const throttle = (func, limit) => {
let inThrottle; // 时间标记
return function () {
if(!inThrottle) {
// 传递参数和指定调用环境
func.apply(this, arguments)
inThrottle = true
setTimeout(() => inThrottle = false, limit)
}
}
}

使用场景

Throttle使用场景主要是大量时间需要按时间分配执行时:

  1. 鼠标在固定区域移动UI变化
  2. DOM元素拖拽

Debounce

函数在被触发N秒后执行,如果在N秒内再被触发,则重新计时⌛️

Debounce函数在设定的时间段内只会被执行一次,如果在这个时间段内被再次触发,则时间重新计算.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// immediate 是否需要立刻执行
const debounce = (func,wait,immediate) {
let timeout;
return function () {
let context = this, args = arguments;
var later = function () {
timeout = null;
if(!immediate) func.apply(context, args);
}
let callNow = !immediate&&!timeout;
clearTimeout(timeout); // 在wait时间段内调用,会移除上个 执行task
timeout = setTimeout(later, wait);
if(callNow) func.apply(context, args);
}
}

使用场景

Debounce使用场景是将多个执行合并成一个执行:

  1. 给按钮加函数防抖防止表单多次提交
  2. scroll 是否滑倒底部判断
  3. input输入框监听用户输入

Demo

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Throttle 和 Debounce</title>
</head>
<body>
<div>
<label for="input1">正常 keyup监听</label>
<input type="text" id="input1"> &nbsp;&nbsp;&nbsp;
<span id="span1"></span>
</div>
<div>
<label for="input2">Throttle keyup监听</label>
<input type="text" id="input2">&nbsp;&nbsp;&nbsp;
<span id="span2"></span>
</div>
<div>
<label for="input3">Debounce keyup监听</label>
<input type="text" id="input3">&nbsp;&nbsp;&nbsp;
<span id="span3"></span>
</div>
</body>
<script>
// 节流函数
const throttle = (func, limit) => {
let inThrottle;
return function () {
if(!inThrottle) {
func.apply(this, arguments)
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}

// 防抖函数
const debounce = (func, wait) => {
let timeout;
return function () {
let context = this, args = arguments;
let later = function () {
func.apply(context, args);
timeout = null;
}
clearTimeout(timeout);
timeout = setTimeout(later, wait);
}
}

const input1 = document.getElementById('input1');
const input2 = document.getElementById('input2');
const input3 = document.getElementById('input3');

const span1 = document.getElementById('span1');
const span2 = document.getElementById('span2');
const span3 = document.getElementById('span3');

input1.addEventListener('keyup', function (event) {
span1.innerText = `${span1.innerText} ${event.target.value} ;`;
})

let throttleFunc = throttle( (value) => {
span2.innerText = `${span2.innerText} ${value} ;`;
}, 1000)

let debounceFunc = debounce( (value) => {
span3.innerText = `${span3.innerText} ${value} ;`;
}, 1000)

input2.addEventListener('keyup', function (event) {
throttleFunc(event.target.value)
})

input3.addEventListener('keyup', function (event) {
debounceFunc(event.target.value)
})

</script>
</html>

👆DEMO运行效果