HOW - 实现 Promise.all()

一、介绍

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

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

示例:

// 示例 所有都成功
const p1 = Promise.resolve(3);
const p2 = 42;
const p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});
// Promise.all([p1, p2, p3])
myPromiseAll([p1, p2, p3])
    .then(results => {
        console.log(results)
    }).catch(error => {
        console.log(error)
    })
  
// 示例 失败即返回
var p4 = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'one');
});
var p5 = new Promise((resolve, reject) => {
    setTimeout(resolve, 2000, 'two');
});
var p6 = new Promise((resolve, reject) => {
    reject('reject');
});
// Promise.all([p4, p5, p6])
myPromiseAll([p4, p5, p6])
    .then(values => {
        console.log(values);
    }, reason => {
        console.log(reason)
    });

二、注意事项

手动实现一个 Promise.all() 需要注意以下几点:

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

  2. 处理空数组情况:如果传入的数组为空,则返回一个立即解决的 Promise 对象,并将解决值设为空数组。

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

  4. 等待所有 Promise 完成:需要等待传入的所有 Promise 对象都解决后才能解决返回的 Promise 对象。为此,可以使用一个计数器来跟踪已解决的 Promise 数量,并在所有 Promise 都解决后解决返回的 Promise 对象。

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

  6. 返回值:返回的 Promise 对象的解决值应该是一个数组,包含传入的所有 Promise 对象解决时的解决值。

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

  8. 保留原始顺序:保留传入的 Promise 数组中 Promise 对象的顺序,确保返回的 Promise 对象的解决值数组与传入的数组中 Promise 对象的顺序相同。

综上所述,手动实现一个 Promise.all() 需要考虑参数验证、空数组情况、Promise 对象的包装、等待所有 Promise 完成、处理拒绝情况、返回值、错误处理以及保留原始顺序等方面的问题。

三、实现

function isPromise(obj) {
	return !!obj && 
		(typeof obj === 'function' || typeof obj === 'object') &&
		typeof obj.then === 'function'
}
function myPromiseAll(promises) {
    // 参数验证
    if (!Array.isArray(promises)) {
        return Promise.reject(new TypeError('参数必须是一个可迭代的对象'));
    }
	// 处理空数组情况
	if (promisesLength === 0) {
		return Promise.resolve([]);
	}
	// 返回一个新的 Promise 对象
	return new Promise((resolve, reject) => {
		let count = 0;
		let promisesLength = promises.length;
		let results = new Array(promisesLength);
		// 遍历传入的 Promise 数组
		for (let i = 0; i < promisesLength; i++) {
			const promiseObj = promises[i];
			if (isPromise(promiseObj)) {
				promiseObj.then(value => {
					results[i] = value;
					count++;
					// 等待所有 Promise 完成
					if (count === promisesLength) {
						return resolve(results);
					}
				}, error => {
					// 处理 reject 情况
					reject(error);
				})
			} else {
				// 处理非 Promise 对象
				results[i] = promiseObj;
				count++;
				// 等待所有 Promise 完成
				if (count === promisesLength) {
					return resolve(results);
				}
			}
		}
	})
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值