2636. Promise 对象池
2025年6月3日大约 2 分钟
2636. Promise 对象池
type F = () => Promise<any>
async function promisePool(functions: F[], n: number): Promise<any[]> {
// 利用数组自身的迭代器,减少变量的维护
const iterator = functions[Symbol.iterator]()
// 任务执行器,存在空闲,主动任务队列拿取新任务执行
async function worker() {
while (true) {
const { value: fn, done } = iterator.next()
if (done) break
await fn()
}
}
// 创建 n 个 worker,每个 worker 会连续取任务执行
const workers = Array.from({ length: n }, () => worker())
// 等待所有 worker 完成
return Promise.allSettled(workers)
}
/**
* const sleep = (t) => new Promise(res => setTimeout(res, t));
* promisePool([() => sleep(500), () => sleep(400)], 1)
* .then(console.log) // After 900ms
*/Promise.all vs Promise.allSettled
| 特性 | Promise.all | Promise.allSettled |
|---|---|---|
| ✅ 全部成功时 | 返回每个 Promise 的结果数组 | 返回每个结果对象,含状态和值或错误 |
| ❌ 任意一个失败时 | 立即 reject,整个结束 | 继续执行所有任务,返回每个任务状态与结果 |
| 📤 结果结构 | [value1, value2, ...] | [{status, value/reason}, ...] |
| ⚠️ 用途 | 所有都要成功的场景(如加载多个资源) | 想知道每个任务结果,不管成功还是失败 |
题目要点
「2636. Promise 对象池」关注的是异步调度语义:并发上限、任务顺序、失败传播以及资源释放时机。
思路拆解
- 先明确时序模型:谁创建任务、谁消费任务、完成后如何回收。
- 把控制逻辑拆成“调度器 + 执行器”,降低状态耦合。
- 明确成功/失败分支的行为是否对齐题目预期(中断、继续或聚合返回)。
复杂度分析
- 时间复杂度:由任务总数与单任务耗时共同决定,调度本身通常是线性的。
- 空间复杂度:关注并发窗口内的任务状态、结果缓存与错误对象。
边界与测试
- 空任务列表、并发数为 1、并发数大于任务数。
- 同时成功与失败的混合输入。
- 长任务与短任务混跑下的顺序与吞吐表现。
工程实践
显式维护任务状态(pending/running/settled),并把异常路径纳入同一返回协议,避免“静默失败”。
总结
异步题的核心不是 API 记忆,而是时序建模能力。只要调度模型清晰,代码可读性和稳定性都会提升。
