直接限制并发请求数量的核心是控制 pending Promise 数不超过阈值,通过队列+计数器实现轻量调度:add() 推入队列,若当前并发数未达阈值则立即执行,否则等待。

直接限制并发请求数量,核心是控制同时处于 pending 状态的 Promise 个数不超过阈值,等有完成再调度下一个。关键不在“池”的包装感,而在调度逻辑的原子性和状态同步。
用队列 + 计数器实现轻量调度
不依赖类或复杂状态机,只维护一个待执行任务队列和当前运行中请求数:
- 每次调用 add() 时,把请求函数推入队列;若当前并发数
- 每个请求 resolve/reject 后,自动递减计数器,并检查队列——若有待办任务且当前并发仍低于阈值,就取出一个执行
- 所有异步操作(如 fetch)必须包裹在 Promise 中,错误需显式 reject,否则计数器卡住
避免 race condition 的关键细节
并发数更新必须同步、不可中断,不能依赖异步回调顺序:
- 用 let running = 0 原始变量而非 this.running 或闭包外状态,确保读写无歧义
- 执行新任务前先 ++running,而不是在 then 里 ++,防止多个 resolve 同时触发导致超限
- reject 也要调用 done(),否则失败请求不释放槽位,池会逐渐“锁死”
支持取消与透传返回值
实际业务常需 abortSignal 和保持原始响应结构:
- add() 接收 (fetcher, options?),其中 options.signal 可透传给 fetch,abort 时也触发 done()
- Promise 返回值直接 resolve 原始响应(或 data),不额外包装,方便上层 .then 处理
- 不实现内部 cancel() 方法——浏览器 fetch 的 signal 已足够,强行加 cancel 会引入冗余状态
示例:6 并发上限的最小可行实现
function createPool(limit = 6) {
const queue = [];
let running = 0;
<p>function done() {
running--;
if (queue.length && running </p><p>return {
add(fetcher) {
const task = () => fetcher().then(done, done);
queue.push(task);
if (running </p><p>// 使用
const pool = createPool(4);
pool.add(() => fetch('/api/a').then(r => r.json()));
pool.add(() => fetch('/api/b').then(r => r.json()));
</p>











