# Async Generators and for await
# Goal: Async Generators and for await
Read the chapter Async iteration and generators (opens new window) of JavaScript.info reproducing the examples and exercises.
# Exercise: for-await-of in a first come first served order
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:
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);
}
}());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Output:
➜ firstcomefirstserved git:(main) node examples/for-await-simple.js
a
x
b
y
c
z
2
3
4
5
6
7
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:
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);
}
})()
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
Output:
➜ 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' }
2
3
4
5
6
7
8
# Error Management Example
Here is an example of how has to behave when there are rejections:
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);
}
})()
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
Gives as output:
➜ 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' }
2
3
4
5
6
7
# Compare the Performance of your solution with the performance of allSettled
Write a program to compare the performance of your solution with the performance of Promise.allSettled (opens new window).
You can find the full code in the npm package frstcmfrstsvd (opens new window).
At first view, performance of Promise.allSettled (opens new window) seems to be a bit better:
> 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
See file examples/performance-reject-frstcmfrstsvd.mjs (opens new window)
# See
- Here is a solution (opens new window). Don't look at it unless you are blocked
- Stackoverflow question: Performance of Promise.all and for-await-of (opens new window)
- ULL-MII-SYTWS-2022/learning-async-iteration-and-generators (opens new window) (Private repo)
- campus-virtual/2021/learning/asyncjs-learning/learning-async-iteration-and-generators
- Chapter Async iteration and generators (opens new window)
- Chapter Iterables (opens new window)
- Chapter Generators (opens new window) of JavaScript.info
# ES6 Modules in Node.JS
- See the Node.js doc Modules: Packages (opens new window) for more details on the use of ECMA 6 Modules in Node.js.
- How Can I use en es6 Import in Node.JS (opens new window) Stackoverflow