Promise 并发方法
在现代 JavaScript 中,处理异步操作时,Promise 是一种常见的工具。在处理多个异步操作时,Promise 提供了几种并发方法:Promise.all、Promise.allSettled、Promise.race 和 Promise.any。这些方法都接收一个 Promise 数组,返回一个新的 Promise。下面我们将依次介绍这些方法的用法及其实现。
1. Promise.all
Promise.all 方法返回一个新的 Promise,当所有输入的 Promise 都被 fulfilled(兑现)时,返回的 Promise 也将被 fulfilled,并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被 rejected(拒绝),则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
实现
Promise.myAll = (promises) => {
return new Promise((resolve, reject) => {
const results = Array(promises.length);
let completedPromises = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then((data) => {
results[index] = data;
completedPromises++;
if (completedPromises === promises.length) {
resolve(results);
}
})
.catch(err => {
reject(err);
});
});
});
}
关键点:我们使用一个 completedPromises 变量来跟踪已完成的 Promise 数量。当 completedPromises 数量等于输入的 Promise 数组长度时,我们调用 resolve 来返回结果数组。
2. Promise.allSettled
Promise.allSettled 方法返回一个新的 Promise,当所有输入的 Promise 都已 settled(即无论是 fulfilled 还是 rejected)时,返回的 Promise 将被 fulfilled,并带有描述每个 Promise 结果的对象数组。
实现
Promise.myAllSettled = (promises) => {
return new Promise((resolve) => {
const res = Array(promises.length);
let completedPromises = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(data => {
res[index] = { status: 'fulfilled', value: data };
})
.catch(error => {
res[index] = { status: 'rejected', reason: error };
})
.finally(() => {
completedPromises++;
if (completedPromises === promises.length) {
resolve(res);
}
});
});
});
}
关键点:Promise.allSettled 总是返回一个 fulfilled 状态的 Promise,无论输入的 Promise 是 fulfilled 还是 rejected,都将其结果记录在结果数组中。
3. Promise.race
Promise.race 方法返回一个新的 Promise,当数组中任意一个 Promise 变为 fulfilled 或 rejected 时,返回的 Promise 也将变为相同状态。换句话说,它返回第一个 settled 的 Promise 的结果。
实现
Promise.myRace = (promises) => {
return new Promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise)
.then(resolve)
.catch(reject);
});
});
}
关键点:Promise.race 会立即返回第一个被 fulfilled 或 rejected 的 Promise,这使得它非常适合处理竞态情况,例如多个异步操作中,只关心最快返回的结果。
4. Promise.any
Promise.any 方法返回一个新的 Promise,只要数组中任意一个 Promise 成功(fulfilled),返回的 Promise 就会被 fulfilled,并带有该成功值。如果所有 Promise 都被拒绝(rejected),则返回的 Promise 将被 rejected,并带有一个 AggregateError,其中包含所有错误信息。
实现
Promise.myAny = (promises) => {
return new Promise((resolve, reject) => {
let rejectCount = 0;
const errors = [];
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(resolve)
.catch(err => {
errors[index] = err;
rejectCount++;
if (rejectCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
});
});
}
关键点:Promise.any 的特点是只要有一个 Promise 成功就会返回成功的结果,而只有所有 Promise 都失败时,才会返回一个 AggregateError。
总结
通过使用 Promise.all、Promise.allSettled、Promise.race 和 Promise.any,我们可以更灵活地处理 JavaScript 中的异步操作。这些方法为不同的并发场景提供了不同的控制策略,使得在编写复杂异步逻辑时,代码更简洁、更具可读性。理解并正确使用这些方法,是编写高效、可维护异步代码的关键。