Promise的并发性方法汇总(包括手写实现)
引言
本文将介绍Promise提供的4个静态方法Promise.all、Promise.allSettled、Promise.any和Promise.race,用于对多个Promise对象进行并发处理。所谓并发处理,就是指同时执行多个异步任务,并根据不同的需求获取它们的结果。
Promise.all
Promise.all(iterable)
入参 iterable
接受一个可迭代对象作为入参。返回值为一个待定 (pending
) 的 promise
对象,根据入参不同分为两种情况:
- 入参为一个空的可迭代对象:返回一个已完成状态的
promise
,fulfilled value
为这个空的可迭代对象; - 入参为一个非空的可迭代对象:
- 在可迭代对象中所有元素都兑现时(若可迭代对象中有非
promise
则直接将其作为兑现结果),返回的promise
状态会由pending
切换为fulfilled
,并将所有结果组成的一个数组作为fulfilled value
(用then
接收); - 若其中有任何一个
promise
被拒绝时,返回的promise
状态会由pending
切换为fulfilled
,并直接报出rejected reason
(用catch
捕获)。
- 在可迭代对象中所有元素都兑现时(若可迭代对象中有非
手写 Promise.all
function all_(promises) {
return new Promise((resolve, reject) => {
const { length } = promises;
// 空的可迭代对象则直接 resolve
if (!length) return resolve(promises);
const rsts = [];
let count = 0;
for (let i = 0; i < length; i++) {
// Promise.resolve() 方法来兼容处理 promise 和非 promise
Promise.resolve(promises[i]).then((e) => {
rsts[i] = e;
if (++count >= length) {
resolve(rsts);
}
}, reject);
}
});
}
Promise.allSettled
Promise.allSettled(iterable)
入参 iterable
接受一个可迭代对象作为入参。与 Promise.all 差不多,返回值为一个待定 (pending
) 的 promise
对象,根据入参不同分为两种情况:
- 入参为一个空的可迭代对象:返回一个已完成状态的 Promise,
fulfilled value
为这个空的可迭代对象;(与 Promise.all 处理方式一致) - 入参为一个非空的可迭代对象:返回的
promise
会在可迭代对象中所有元素都兑现或被拒绝时(若可迭代对象中有非promise
则直接将其作为兑现结果),将所有的处理结果(一个对象,包含fulfilled
orrejected
的状态)组成一个数组作为fulfilled value
(用then
接收)。- 返回的兑现结果
PromiseAllSettledFulfilledValue
(笔者自定义的一个类型,为方便解释)的类型如下:
- 返回的兑现结果
type PromiseAllSettledFulfilledValue = {
status: 'fulfilled' | 'rejected'; // 处理结果状态
value?: unknown; // fulfilled value
reason?: unknown; // rejected reason
}[];
手写 Promise.allSettled
function allSettled_(promises) {
return new Promise((resolve) => {
const { length } = promises;
if (!length) return resolve(promises);
const rsts = [];
let count = 0;
const resolveRsts = (i: number, e: { status: 'fulfilled' | 'rejected'; value?: unknown; reason?: unknown }) => {
rsts[i] = e;
if (++count >= length) {
resolve(rsts);
}
};
for (let i = 0; i < length; i++) {
Promise.resolve(promises[i]).then(
(e) =>
resolveRsts(i, {
status: 'fulfilled',
value: e,
}),
(e) =>
resolveRsts(i, {
status: 'rejected',
reason: e,
})
);
}
});
}
Promise.any
Promise.any(iterable)
入参 iterable
接受一个可迭代对象作为入参。与 Promise.all 类似,返回值为一个待定 (pending
) 的 promise
对象,根据入参不同分为两种情况:
- 入参为一个空的可迭代对象:返回一个已经被拒的
promise
,rejected reason
为这个空的可迭代对象;(注意这里与 Promise.all 处理方式的区别,这里是reject
) - 入参为一个非空的可迭代对象:
- 在可迭代对象中的任意一个元素兑现时(若可迭代对象中有非
promise
则直接将其作为兑现结果),返回的promise
状态会由pending
切换为fulfilled
,并直接将该结果作为fulfilled value
(用then
接收); - 若所有
promise
都被拒绝了,返回的promise
状态会由pending
切换为rejected
,并用一个AggregateError
实例来作为它的rejected reason
(用catch
接收)。
- 在可迭代对象中的任意一个元素兑现时(若可迭代对象中有非
interface AggregateError {
message: string; // 错误消息
name: 'AggregateError'; // 错误名称
errors?: unknown[]; // 错误列表
}[];
手写 Promise.any
function any_(promises) {
return new Promise((resolve, reject) => {
const { length } = promises;
if (!length) return reject(new AggregateError(promises, 'All promises were rejected'));
const reasons = [];
let count = 0;
for (let i = 0; i < length; i++) {
Promise.resolve(promises[i]).then(resolve, (e) => {
reasons[i] = e;
if (++count >= length) {
reject(new AggregateError(reasons, 'All promises were rejected'));
}
});
}
});
}
Promise.race
Promise.race(iterable)
入参 iterable
接受一个可迭代对象作为入参,返回值为一个待定 (pending
) 的 promise
对象,只要给定的迭代对象中的一个元素(若可迭代对象中有非 promise
则直接将其作为兑现结果)兑现或被拒绝,就采用第一个兑现或拒绝的元素的处理结果来 resolve
或 reject
。(若入参为空迭代对象,则表示没有元素兑现或被拒绝,返回值 promise
对象将一直处于 pending
状态。)
手写 Promise.race
function race_(promises) {
return new Promise((resolve, reject) => {
for (const p of promises) {
Promise.resolve(p).then(resolve, reject);
}
});
}
全部代码及对比测试
解释:以下代码片段中将上述手写函数添加至 Promise
的静态方法中,并与原始方法进行对比测试,输出结果均为一致。
总结
Promise的并发性方法常用于处理多个promise的并发执行问题,每个方法应用场景大致总结如下:
- Promise.all:用于接收多个promise兑现的结果,若其中有reject的会被reject
- Promise.allSettled:用于接收多个promise兑现/拒绝的结果
- Promise.any:用于接收多个promise中兑现最快的那个的兑现结果,若全部reject则reject
- Promise.race:用于接收多个promise中兑现/拒绝最快的那个的处理结果
转载自:https://juejin.cn/post/7213298252536266810