手写 Promise.all
题目:复刻
Promise.all:接收一个可迭代对象,所有 promise 都 fulfilled 时按顺序返回结果数组;任何一个 reject 则立即 reject。
1. 正常使用示例
下面为 Promise.all 的功能展示。正常情况下我们应该输出数组对象 [1, 2, 3]。
let promise1 = new Promise(function(resolve) {
resolve(1);
});
let promise2 = new Promise(function(resolve) {
resolve(2);
});
let promise3 = new Promise(function(resolve) {
resolve(3);
});
let promiseAll = Promise.all([promise1, promise2, promise3]);
promiseAll.then(function(res) {
console.log(res);
});
2. 最简实现(有缺陷)
Promise.all = function(promises) {
let results = [];
return new Promise(function(resolve) {
promises.forEach(function(val) {
// 按顺序执行每一个Promise操作
val.then(function(res) {
results.push(res);
});
});
resolve(results);
});
}
上面是最简化的版本,但是也有两个问题:一、Promise.all 传递的参数可能不是 Promise 类型,可能不存在 then 方法;二、如果中间发生错误,应该直接返回错误,不执行后面操作。
3. 改造版本(最终实现)
Promise.prototype.all = function (promises) {
let results = [];
let promiseCount = 0;
const promisesLength = promises.length;
return new Promise(function (resolve, reject) {
for (let i = 0; i < promisesLength; i++) {
Promise.resolve(promises[i]).then(
function (res) {
promiseCount++;
results[i] = res; // 用闭包中的 i 保留位置,保证顺序
if (promiseCount === promisesLength) {
return resolve(results);
}
},
function (err) {
return reject(err);
}
);
}
});
};
补充:
results[i] = res必须保留原始下标i,否则多个异步任务完成后会按完成顺序写入,导致最终数组顺序错乱。原笔记里直接写results[i]漏掉了闭包外层的let i,需要换成const i或用forEach。
来源整理自:vue3js.cn 面试官系列



