节流
Alphawq
# 使用 setTimeout 实现
- 首次触发事件,不会执行回调
- 停止触发事件,则 wait 时间过后还会执行一次回调
function throttle(fn, wait) {
let timer = null
let args = void 0
return function () {
args = arguments
if (timer) return
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, wait)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 不使用 setTimeout 实现
- 第一次触发 fn 会立即执行
- 最后一次触发事件之后,fn 不会再执行
function throttle(fn, wait) {
let pre = 0
return function () {
let now = Date.now()
if (now - pre >= wait) {
pre = now
fn.apply(this, arguments)
}
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 结合实现
// 优化:组合上述两种方式
// 两者不能同时为false
// options: {
// leading:false 表示禁用第一次执行
// trailing: false 表示禁用停止触发的回调
// }
function throttle(fn, wait, options) {
let pre = 0
let timer = null
let args
let context = null
options = options || {}
let later = () => {
// 如果设置了禁用第一次执行
pre = options.leading === false ? 0 : Date.now()
timer = null
fn.call(context, args)
}
return function () {
args = arguments
context = this
let now = Date.now()
// 如果是第一次触发,并且禁用第一次执行
if (!pre && options.leading === false) pre = now
// 计算距离下一次执行的剩余时间
let remaining = wait - (now - pre)
// 如果到了执行的时间了
if (remaining <= 0) {
// 先判断有没有正在运行的定时器,没有的话直接执行
if (!timer) {
// 更新执行时间
pre = now
fn.call(this, ...arguments)
} else {
clearTimeout(timer)
timer = null
}
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining)
}
}
}
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
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