前端面试 P097:请求并发池、任务启动与失败释放
来源:方格前端讲面试 · 如何解决页面请求接口大规模并发问题,15 分 37 秒。
回看定位:01:13 并发方案 · 05:01 队列
限制同时执行数,而不是已经开始的 Promise 数
把任务保存为函数,轮到额度才调用。Promise.all 只组合结果,不会把已发出的数百个请求变成受控队列。
function createLimit(maximum) {
if (!Number.isInteger(maximum) || maximum < 1) throw new RangeError('Invalid limit');
let active = 0;
const queue = [];
function drain() {
while (active < maximum && queue.length) {
const job = queue.shift();
active++;
Promise.resolve().then(job.task).then(job.resolve, job.reject)
.finally(() => { active--; drain(); });
}
}
return task => new Promise((resolve, reject) => {
if (typeof task !== 'function') { reject(new TypeError('Expected task')); return; }
queue.push({ task, resolve, reject });
drain();
});
}
同步 throw、异步拒绝和成功都释放额度,调用方仍通过返回 Promise 获得本项结果。FIFO 排队不代表完成顺序相同;需要按输入顺序汇总时可对这些返回 Promise 使用 all 或 allSettled。
还需设计的策略
队列上限与背压、超时、AbortSignal、优先级、饥饿、取消未启动任务和正在执行任务应明确。这个基础版本不支持自动取消或去重,任务不结束会持续占额度。
对课程整体优化建议的补充
节流、防抖、合并、缓存与服务端优化处理不同问题。HTTP/2 多路复用不代表无限并发无代价,CDN 也不能无条件缓存用户私有 SSR 响应;数据库索引不是越多越好。
根据实测瓶颈选择额度,考虑服务端限流、429 与 Retry-After;自动重试要带退避、抖动和总预算,不制造重试风暴。