问题的一部分是,如果你在一个 Promise 数组上使用 for-await-of,你会按照指定的顺序迭代它,如果给定数组中的下一个 Promise 在前一个 Promise 之前解决,这无关紧要:
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
(async function () {
const arr = [
sleep(2000).then(() => 'a'),
'x',
sleep(1000).then(() => 'b'),
'y',
sleep(3000).then(() => 'c'),
'z',
];
for await (const item of arr) {
console.log(item);
}
}());
输出:
➜ firstcomefirstserved git:(main) node examples/for-await-simple.js
a
x
b
y
c
z
但有时 - 就像您的问题一样,您希望在承诺产生结果后立即处理结果。所以我决定编写一个异步迭代器,让for await 以首先承诺解决是首先被服务的方式工作。代码如下:
// promises is an Array not an Iterable
async function* auxIterator(promises) {
let wrappedPromises = promises.map((p, i) => {
return new Promise((resolve, reject) => {
p.then(r => resolve([r,i]))
.catch(e => reject(e))
})
});
let [r, i] = await Promise.race(wrappedPromises);
yield r;
promises.splice(i,1);
if (promises.length)
yield * auxIterator(promises)
}
async function * frstcmfrstsvd(promises) {
let wrappedPromises = promises.map((p, i) => {
return new Promise((resolve, reject) => {
Promise.resolve(p).then(r => resolve({value: r, index: i, status: 'fulfilled'}))
.catch(e => resolve({reason: e, index: i, status: 'rejected'}))
})
});
yield * await auxIterator(wrappedPromises);
}
export default frstcmfrstsvd
你可以在npm包frstcmfrstsvd中找到完整代码。
还没有详尽的测试,但乍一看,Promise.allSettled 的性能似乎要好一些:
> node examples/performance-reject-frstcmfrstsvd.mjs
frstcmfrstsvd: 323.104ms
allsettled: 317.319ms
> node examples/performance-reject-frstcmfrstsvd.mjs
frstcmfrstsvd: 327.142ms
allsettled: 315.415ms
> node examples/performance-reject-frstcmfrstsvd.mjs
frstcmfrstsvd: 322.753ms
allsettled: 318.955ms
> node examples/performance-reject-frstcmfrstsvd.mjs
frstcmfrstsvd: 325.562ms
allsettled: 317.375ms
> node examples/performance-reject-frstcmfrstsvd.mjs
frstcmfrstsvd: 322.25ms
allsettled: 318.09ms
查看文件examples/performance-reject-frstcmfrstsvd.mjs
因此,所有这个实验的结论似乎是正如@jonas-wilms 所说,它们大致同时完成