实现 Promise.any
手写 Promise.any 方法
问题
从零实现 Promise.any 方法。Promise.any 接收一组 Promise,只要有一个成功就返回该结果;全部失败则抛出 AggregateError。
解答
Promise.myAny = function (promises) {
return new Promise((resolve, reject) => {
// 转换为数组
const promiseArr = Array.from(promises);
// 空数组直接拒绝
if (promiseArr.length === 0) {
reject(new AggregateError([], 'All promises were rejected'));
return;
}
const errors = []; // 收集所有错误
let rejectedCount = 0;
promiseArr.forEach((promise, index) => {
// 包装非 Promise 值
Promise.resolve(promise).then(
// 任意一个成功,立即 resolve
(value) => resolve(value),
// 失败则记录错误
(error) => {
errors[index] = error;
rejectedCount++;
// 全部失败,抛出 AggregateError
if (rejectedCount === promiseArr.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
};
测试
// 测试1:有成功的情况
const p1 = Promise.reject('error1');
const p2 = Promise.resolve('success');
const p3 = Promise.reject('error3');
Promise.myAny([p1, p2, p3]).then(console.log); // 'success'
// 测试2:全部失败
const p4 = Promise.reject('error1');
const p5 = Promise.reject('error2');
Promise.myAny([p4, p5]).catch((e) => {
console.log(e instanceof AggregateError); // true
console.log(e.errors); // ['error1', 'error2']
});
// 测试3:空数组
Promise.myAny([]).catch((e) => {
console.log(e.message); // 'All promises were rejected'
});
关键点
- 任意一个 Promise 成功就立即 resolve,不等待其他
- 全部失败时抛出
AggregateError,包含所有错误 - 用
Promise.resolve()包装输入,兼容非 Promise 值 - 错误数组要保持原始索引顺序
- 空数组直接拒绝,返回空的
AggregateError
目录