基础防抖#
1
2
3
4
5
6
7
8
9
10
11
12
| const _debounce = (fn, delay, immediate = false) => {
let timer;
return (...args) => {
const callNow = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (!immediate) fn(...args);
}, delay);
if (callNow) fn(...args);
};
};
|
带 Promise 的防抖#
拖拽鼠标时若频繁触发防抖,而被包装函数会请求 API 并返回 Promise,往往只希望最后一次调用生效。Lodash 的 debounce 会校验 func 必须是函数:
1
2
3
| if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
|
异步场景可以这样写:
只保留最后一次 Promise#
1
2
3
4
5
6
7
8
9
10
11
12
| const debounce_promise_last = (fn, delay) => {
let timer = null;
return (...args) => {
clearTimeout(timer);
return new Promise((resolve) => {
timer = setTimeout(
() => resolve(fn(...args)),
delay,
);
});
};
};
|
每次调用都返回 Promise,延迟后一起 resolve#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| function debounce_promise_all(fn, delay = 0) {
let timer = null;
let resolves = [];
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
const result = fn(...args);
resolves.forEach((r) => r(result));
resolves = [];
}, delay);
return new Promise((r) => resolves.push(r));
};
}
|
API 调用:节流、取消、重试#
调 API 时常用节流限制单位时间内的请求次数。更复杂的情况包括取消和重试(指数退避)。当并发 Promise 非常多(例如 1000+)时,通常需要:
- 分批处理(如每批 20 个);
- 为每个 Promise 绑定任务 ID;
- 单条日志便于排查(我们使用 Splunk);
- 设计取消策略;
- Ajax 重试使用指数退避。
实现与产品逻辑耦合较紧,此处不展开示例代码。