Promise 的异步任务并发函数
Promise.race 传入的数组可以动态变化么?
// 解答标题:可以动态数组,即使第一次执行 Promise.race([A,B,C]) 时每个 promise 都被触发了,Promise.race([B,C,D]) 还是可以返回第一个 非待定状态的 promise
Promise 的异步任务并发函数 4个:Promise.all
Promise.allsettled
Promise.race
Promise.any
- Promise.race [总是异步的] - 返回第一个非待定状态的 Promise
- 若传入空数组,则返回的 promise 一直保持 pending 状态
- 若传入的数组全是已经敲定的 promise ,但返回的 promise 依旧是异步敲定
- 若传入 非Promise值xN 或 已经敲定的 promisexN,则找到第一个这样的值返回
- Promise.all
- 若数组所有 promise 被兑现,则返回一个兑现状态 promise + 数组
- 若数组任何 promise 被拒绝,则返回一个拒绝状态 promise + 拒绝原因
- Promise.any [总是异步的] - 返回第一个兑现的 Promise
- 若传入空数组,则返回的 promise 是 rejected 状态
- 任何一个 promise 被敲定[兑现],则返回的 promise 异步兑现
- 若传入的数组全是被拒绝的,则返回的 promise 异步拒绝 + 原因数组
// AggregateError: No Promise in Promise.any was resolved
- Promise.allsettled - 返回一个兑现的 promise,并描述每个 promise 结果的数组
2、源码模拟实现
MyPromise.race = function (arr) {
return new MyPromise((resolve, reject) => {
arr.forEach(it => MyPromise.resolve(it).then(resolve).catch(reject)) // 更推荐,原因:在某些复杂的链式调用中,能更清晰地将成功和失败的处理逻辑分开,提高代码的可读性和可维护性
// 之前的写法:arr.forEach(it => MyPromise.resolve(it).then(resolve, reject))
});
};
MyPromise.all = function (arr) {
return new MyPromise((resolve, reject) => {
if (arr.length === 0) { resolve([]); return; } // arr 为空数组时,forEach 不会执行
const results = new Array(arr.length);
let completedCount = 0; // 计数器
arr.forEach((it, index) => { // 遍历所有 promises
MyPromise.resolve(it).then((res) => {
results[index] = res;
completedCount++;
if (completedCount === arr.length) { resolve(results) } // 返回结果
}).catch(reject);
});
});
};
MyPromise.allSettled = function (arr) {
return new MyPromise((resolve) => {
const results = [];
let completedCount = 0;
if (arr.length === 0) { resolve([]); return; } // arr 为空数组时
arr.forEach((promise, index) => {
MyPromise.resolve(promise).then((value) => {
results[index] = { status: 'fulfilled', value };
}).catch((reason) => {
results[index] = { status: 'rejected', reason };
}).finally(() => {
completedCount++;
if (completedCount === arr.length) { resolve(results) } // 返回结果
});
});
});
};
const getErr = (info) => new AggregateError(info, 'All promises were rejected');
MyPromise.any = function (arr) {
return new MyPromise((resolve, reject) => {
const errors = [];
let count = 0;
if (arr.length === 0) { reject(getErr([])); return; }
arr.forEach((promise, index) => {
MyPromise.resolve(promise).then(resolve).catch((error) => {
errors[index] = error;
count++;
if (count === arr.length) { reject(getErr(errors));}
});
});
});
};