HOW - 实现 Promise.any()

一、介绍

MDN Web docs 官方介绍:Promise.any()

The Promise.any() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when any of the input’s promises fulfills, with this first fulfillment value. It rejects when all of the input’s promises reject (including when an empty iterable is passed), with an AggregateError containing an array of rejection reasons.

示例:

const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));
const promises = [promise1, promise2, promise3];
Promise.any(promises).then((value) => console.log(value));
// Expected output: "quick"

二、注意事项

手动实现一个 Promise.any() 方法时需要注意以下几点:

  1. 参数验证:需要确保传入的参数是一个可迭代的对象,例如数组或类数组对象。

  2. 处理空数组情况:如果传入的数组为空,则返回一个立即拒绝的 Promise 对象,因为没有任何 Promise 可以被解决。

  3. 处理非 Promise 对象:需要确保传入的数组中的每个元素都是 Promise 对象,如果有任何一个元素不是 Promise 对象,则需要将其包装为 Promise 对象。

  4. 等待第一个 Promise 解决:需要等待传入的所有 Promise 对象中的第一个解决。为此,可以使用一个循环来遍历传入的 Promise 数组,并在第一个 Promise 解决后解决返回的 Promise 对象。

  5. 处理拒绝情况:如果传入的所有 Promise 对象都拒绝(即状态都变为 rejected),则返回的 Promise 对象也应该立即拒绝,并且使用传入的所有 Promise 的拒绝原因作为自己的拒绝原因。

  6. 处理多次调用:一旦有一个 Promise 对象解决,返回的 Promise 对象应该立即解决,并且忽略后续的 Promise 对象。

  7. 错误处理:需要捕获可能发生的错误,并将其作为拒绝原因传递给返回的 Promise 对象。

综上所述,手动实现一个 Promise.any() 需要考虑参数验证、空数组情况、Promise 对象的包装、等待第一个 Promise 解决、处理拒绝情况、处理多次调用以及错误处理等方面的问题。

三、实现

其实可以发现,any 和 all 是相反的一个方法,后者需要判断是否全部 resolved,前者需要判断是否全部 reject。

function isPromise(obj) {
	return !!obj && 
		(typeof obj === 'function' || typeof obj === 'object') &&
		typeof obj.then === 'function'
}
function myPromiseAny(promises) {
    // 参数验证
    if (!Array.isArray(promises)) {
        return Promise.reject(new TypeError('参数必须是一个可迭代的对象'));
    }
    // 处理空数组情况
    if (promises.length === 0) {
        return Promise.reject(new AggregateError('No promises passed'));
    }
    // 返回一个新的 Promise 对象
    return new Promise((resolve, reject) => {
        let errors = [];
        let count = 0; // completed
        // 遍历传入的 Promise 数组
        for (const promise of promises) {
            // 处理非 Promise 对象
            // if (!(promise instanceof Promise)) {
            if (!isPromise(promise)) {
                promise = Promise.resolve(promise);
            }
            // 处理每个 Promise 的解决和拒绝
            promise.then(
                // 解决处理程序
                (value) => resolve(value),
                // 拒绝处理程序
                (reason) => {
                    errors.push(reason);
                    count++;
                    // 如果所有 Promise 都拒绝,则返回一个 AggregateError
                    if (count === promises.length) {
                        reject(new AggregateError(errors));
                    }
                }
            );
        }
    });
}

// 测试
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => reject('Promise 1 rejected'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Promise 2 resolved'), 500);
});
myPromiseAny([promise1, promise2])
    .then((value) => console.log('First promise resolved:', value))
    .catch((error) => console.error('All promises rejected:', error));
  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值