怎样实现保持输入顺序的 Promise.all 教学版本?
参考答案
核心是把每个结果写回输入索引,用计数判断是否全部完成。普通值与 thenable 通过 Promise.resolve 统一处理;某项拒绝时整体拒绝,但不会取消其他已启动操作。
下面是本项目编写的教学版本,返回原生 Promise,支持常规可迭代输入;不模拟原生方法对子类构造器、被改写的内建方法等全部规范细节。生产代码优先使用原生 Promise.all。
JavaScript
function promiseAll(iterable) {
return new Promise((resolve, reject) => {
const results = [];
let remaining = 1; // 保留一个计数,避免遍历结束前提前完成
let index = 0;
for (const item of iterable) {
const position = index++;
remaining++;
Promise.resolve(item).then(value => {
results[position] = value;
if (--remaining === 0) resolve(results);
}, reject);
}
if (--remaining === 0) resolve(results);
});
}
空输入得到空数组;完成顺序不同也不改变结果顺序。不可迭代输入或迭代过程抛错,会通过 Promise 构造器转成拒绝。这里的聚合不是并发数限制器:传入已经执行的异步任务,无法让它们回到尚未启动的状态。