简化 Promise.all
先理解原理和示例,再练习完整口述与追问。
回答要点
接受可迭代对象;吸收普通值和 thenable;保序;空输入;拒绝传播。
原理拆解
简化 Promise.all 的关键是按输入位置保存结果并统计完成数量,而不是按返回速度 push。每项要按 Promise 采纳规则处理,普通值也能参与;空输入要立即得到空数组。单个拒绝决定组合结果,但已开始的其他任务仍可能继续执行。
示例与推演
三个任务按 2、0、1 的顺序完成,结果仍应放到索引 0、1、2;每个成功仅减少一次剩余量,全部结束再 resolve。验证普通数字、空数组、立即拒绝、慢任务和 thenable;输入读取或迭代抛错也应按支持范围处理。
易错点
示例若只支持数组,不能称完整原生替代。组合器不提供真正取消和并发限制。
参考回答可直接练习口述
每项先通过 Promise.resolve 统一处理,结果写回输入下标;用计数判断全部完成。有任一失败就拒绝,已开始的其他任务不会因此取消。下面用一个初始计数哨兵兼顾空迭代,迭代器同步抛错会由 Promise 执行器转成拒绝;不实现子类构造等完整原生细节。
function promiseAll(iterable) {
return new Promise((resolve, reject) => {
const results = []
let remaining = 1
let index = 0
for (const item of iterable) {
const current = index++
remaining++
Promise.resolve(item).then(value => {
results[current] = value
if (--remaining === 0) resolve(results)
}, reject)
}
if (--remaining === 0) resolve(results)
})
}
示例:await promiseAll([Promise.resolve(1),2]) 得到 [1,2];空 Set 得到 [];输入 null 得到拒绝。空间 O(n),调度额外工作 O(n),完成时间取决于任务。若要限制启动数量,应使用下一题的函数工厂队列,而不是提前创建所有 Promise。Promise.all 行为依据