防抖和他的进阶写法

防抖的核心思想是:在事件触发后,先等待一段时间,如果在这段时间内没有再次触发事件,则执行回调;如果在这段时间内时间又被触发,则重新计时。

应用场景

  • 输入框实时搜索(等待用户输入完成后再发送请求)。
  • 窗口大小调整(等待用户停止调整后再计算布局)。

手写实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function debounce(func, delay) {
let timer = null; // 用于存储定时器

return function (...args) {
const context = this; // 保存当前上下文

// 如果定时器存在,则清除之前的定时器
if (timer) {
clearTimeout(timer);
}

// 重新设置定时器
timer = setTimeout(() => {
func.apply(context, args); // 延迟结束后执行函数
}, delay);
};
}

3. 进阶:支持立即执行的防抖

有时候我们需要在事件触发时立即执行一次函数,然后再进入防抖模式。以下是支持立即执行的防抖实现:

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
function debounce(func, delay, immediate = false) {
let timer = null;

return function (...args) {
const context = this;

// 如果定时器存在,则清除之前的定时器
if (timer) {
clearTimeout(timer);
}

// 如果需要立即执行
if (immediate && !timer) {
func.apply(context, args); // 立即执行函数
}

// 设置定时器
timer = setTimeout(() => {
timer = null; // 重置定时器
if (!immediate) {
func.apply(context, args); // 延迟结束后执行函数
}
}, delay);
};
}

4. 进阶:支持取消的防抖

有时候我们需要在特定条件下取消防抖或节流的执行。以下是支持取消的实现:

防抖(支持取消)

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
function debounce(func, delay) {
let timer = null;

const debounced = function (...args) {
const context = this;

if (timer) {
clearTimeout(timer);
}

timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};

// 添加取消方法
debounced.cancel = function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
};

return debounced;
}

使用建议

通过手写,可以更好地理解它们的原理和应用场景。在实际开发中,请直接使用 Lodash 等工具库提供的 debounce 方法。

1
_.debounce(func, [wait=0], [options=])