简化 Promise.all

先理解原理和示例,再练习完整口述与追问。

接受可迭代对象;吸收普通值和 thenable;保序;空输入;拒绝传播。

简化 Promise.all 的关键是按输入位置保存结果并统计完成数量,而不是按返回速度 push。每项要按 Promise 采纳规则处理,普通值也能参与;空输入要立即得到空数组。单个拒绝决定组合结果,但已开始的其他任务仍可能继续执行。

三个任务按 2、0、1 的顺序完成,结果仍应放到索引 0、1、2;每个成功仅减少一次剩余量,全部结束再 resolve。验证普通数字、空数组、立即拒绝、慢任务和 thenable;输入读取或迭代抛错也应按支持范围处理。

示例若只支持数组,不能称完整原生替代。组合器不提供真正取消和并发限制。

每项先通过 Promise.resolve 统一处理,结果写回输入下标;用计数判断全部完成。有任一失败就拒绝,已开始的其他任务不会因此取消。下面用一个初始计数哨兵兼顾空迭代,迭代器同步抛错会由 Promise 执行器转成拒绝;不实现子类构造等完整原生细节。

js
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 行为依据