Master de II. ULL. 1er cuatrimestre
If you use for-await-of on an array of promises, you iterate over it in the specified order, doesn’t matter if the next promise in the given array is resolved before the previous one:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
}
}());
Output:
1
2
3
4
5
6
7
➜ firstcomefirstserved git:(main) node examples/for-await-simple.js
a
x
b
y
c
z
But sometimes you want to process the results as soon as the promises yield them.
Write a Node.JS module frstcmfrstsvd
that exports an async generator that can be used with for-await-of and provides the results in a first come first served order:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import firstComeFirstServed from 'frstcmfrstsvd';
// See https://stackoverflow.com/questions/40920179/should-i-refrain-from-handling-promise-rejection-asynchronously
process.on('rejectionHandled', () => { });
process.on('unhandledRejection', error => {
console.log('unhandledRejection');
});
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
const arr = [
sleep(2000).then(() => 'a'),
'x',
sleep(1000).then(() => 'b'),
'y',
sleep(3000).then(() => 'c'),
'z',
];
console.log(firstComeFirstServed);
(async () => {
for await (let item of firstComeFirstServed(arr)) {
console.log("item = ",item);
}
})()
Output:
1
2
3
4
5
6
7
8
➜ firstcomefirstserved git:(main) node examples/hello-frstcmfrstsvd.mjs
[AsyncGeneratorFunction: frstcmfrstsvd]
item = { value: 'x', index: 1, status: 'fulfilled' }
item = { value: 'y', index: 3, status: 'fulfilled' }
item = { value: 'z', index: 5, status: 'fulfilled' }
item = { value: 'b', index: 2, status: 'fulfilled' }
item = { value: 'a', index: 0, status: 'fulfilled' }
item = { value: 'c', index: 4, status: 'fulfilled' }
Here is an example of how has to behave when there are rejections:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import frstcmfrstsvd from 'frstcmfrstsvd';
// See https://stackoverflow.com/questions/40920179/should-i-refrain-from-handling-promise-rejection-asynchronously
process.on('rejectionHandled', () => { });
process.on('unhandledRejection', error => {
console.log('unhandledRejection');
});
const sleep = time =>
new Promise(resolve => setTimeout(resolve, time));
const arr = [
sleep(2000).then(() => 'a'),
'x',
sleep(1000).then(() => 'b'),
'y',
sleep(3000).then(() => { throw `Ohhh:\n` }),
'z',
];
(async () => {
try {
for await (let item of frstcmfrstsvd(arr)) {
console.log("item = ",item);
}
} catch(e) {
console.log('Catched!:\n', e);
}
})()
Gives as output:
1
2
3
4
5
6
7
➜ firstcomefirstserved git:(main) ✗ node examples/reject-frstcmfrstsvd.mjs
item = { value: 'x', index: 1, status: 'fulfilled' }
item = { value: 'y', index: 3, status: 'fulfilled' }
item = { value: 'z', index: 5, status: 'fulfilled' }
item = { value: 'b', index: 2, status: 'fulfilled' }
item = { value: 'a', index: 0, status: 'fulfilled' }
item = { reason: 'Ohhh:\n', index: 4, status: 'rejected' }
Write a program to compare the performance of your solution with the performance of Promise.allSettled.
You can find the full code in the npm package frstcmfrstsvd.
At first view, performance of Promise.allSettled seems to be a bit better:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> 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
See file examples/performance-reject-frstcmfrstsvd.mjs