防抖(debounce)和节流(throttle)

防抖(debounce)和节流(throttle)

防抖和节流的目的都是希望一段时间内不要密集调用callback。

应用场景:滚动(防抖),搜索(节流)

防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

有些事件比如 resize, scroll, mousemove 等会被持续的触发,导致 callback 被高频调用,这就要用到防抖。

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
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func, wait, immediate) {
let timeout;

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

if (timeout) clearTimeout(timeout);

if (immediate) {
var callNow = !timeout;

timeout = setTimeout(() => {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
}
};
}

节流

所谓节流,就是指连续触发事件但是在 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
33
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait, type) {
if (type === 1) {
let previous = 0;
} else if (type === 2) {
let timeout;
}
return function() {
let context = this;
let args = arguments;

if (type === 1) {
let now = Date.now();

if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
}
};
}

总结

防抖是控制次数,节流是控制频率。

ref

  1. 简版 debounce 和 throttle

评论