实现 Promise.all
手写实现 Promise.all 方法,接收一个 Promise 数组并返回一个新的 Promise,当所有 Promise 都成功时返回结果数组,任一失败则立即返回失败原因。
问题
Promise.all 是 JavaScript 中用于处理多个异步操作的重要方法。它接收一个可迭代对象(通常是 Promise 数组),返回一个新的 Promise。当所有输入的 Promise 都成功时,返回的 Promise 才会成功,结果是所有 Promise 结果组成的数组;只要有一个 Promise 失败,返回的 Promise 就会立即失败,返回第一个失败的原因。
解答
/**
* 实现 Promise.all
* @param {Iterable} promises - 可迭代对象,通常是 Promise 数组
* @returns {Promise} 返回一个新的 Promise
*/
function promiseAll(promises) {
return new Promise((resolve, reject) => {
// 将可迭代对象转换为数组
const promiseArray = Array.from(promises);
// 处理空数组的情况
if (promiseArray.length === 0) {
resolve([]);
return;
}
// 用于存储结果的数组
const results = [];
// 记录已完成的 Promise 数量
let completedCount = 0;
// 遍历所有 Promise
promiseArray.forEach((promise, index) => {
// 使用 Promise.resolve 包装,确保非 Promise 值也能正常处理
Promise.resolve(promise)
.then(value => {
// 将结果存储到对应的索引位置,保证顺序
results[index] = value;
completedCount++;
// 当所有 Promise 都完成时,resolve 结果数组
if (completedCount === promiseArray.length) {
resolve(results);
}
})
.catch(error => {
// 任何一个 Promise 失败,立即 reject
reject(error);
});
});
});
}
使用示例
// 示例 1: 所有 Promise 都成功
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 1000);
});
promiseAll([p1, p2, p3])
.then(results => {
console.log(results); // 输出: [1, 2, 3]
})
.catch(error => {
console.error(error);
});
// 示例 2: 有 Promise 失败
const p4 = Promise.resolve(4);
const p5 = Promise.reject('Error occurred');
const p6 = Promise.resolve(6);
promiseAll([p4, p5, p6])
.then(results => {
console.log(results);
})
.catch(error => {
console.error(error); // 输出: Error occurred
});
// 示例 3: 包含非 Promise 值
promiseAll([1, 2, Promise.resolve(3)])
.then(results => {
console.log(results); // 输出: [1, 2, 3]
});
// 示例 4: 空数组
promiseAll([])
.then(results => {
console.log(results); // 输出: []
});
关键点
-
使用
Array.from转换可迭代对象:确保输入可以是任何可迭代对象,不仅限于数组 -
空数组边界处理:当输入为空数组时,应立即 resolve 一个空数组
-
使用
Promise.resolve包装:确保数组中的非 Promise 值也能被正确处理,统一转换为 Promise -
保持结果顺序:使用索引
results[index]存储结果,而不是push,确保结果数组的顺序与输入数组一致 -
计数器机制:使用
completedCount记录已完成的 Promise 数量,当等于总数时才 resolve -
快速失败机制:任何一个 Promise 失败时立即 reject,不等待其他 Promise 完成
-
避免重复 resolve/reject:一旦某个 Promise 失败并 reject 后,其他 Promise 的结果将被忽略
目录