Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at the best features of ES2018.
Async Iteration
With ES6, JavaScript introduced the for-of loop.
It lets us synchronously iterate through iterable objects.
However, there’s no way to iterate asynchronously.
ES2018 introduced the async iteration feature to fill this gap.
Synchronous iteration works with any object that has the Symbol.iterator
method, which is a generator method.
It returns each item with sequentially when the next
next method is called.
The returned object has the value returned from the generator, which is the current entry that the iterator hits.
It also has the done
property to indicate whether all th values have been returned.
For instance, if we have:
const iterable = ['foo', 'bar'];
const iterator = iterable[Symbol.iterator]();
Then when we call:
iterator.next()
the first time, we get:
{ value: 'foo', done: false }
Then when we call it again, we get;
{ value: 'b', done: false }
And when we call it one more time, we get:
{ value: undefined, done: true }
The iteration is synchronous, so we can’t iterate asynchronously.
We want to be able to call promises in an iterable object one by one.
This is solved with the for-await-of loop.
For instance, we can use it by writing:
async function main() {
const arr = [
Promise.resolve('foo'),
Promise.resolve('bar'),
];
for await (const x of arr) {
console.log(x);
}
}
main();
We have an array of promises that we iterate through.
They’ll be run one by one.
So we get:
foo
bar
logged in the console log.
The for-await-of loop also works with synchronous iterables.
So we can write:
async function main() {
for await (const x of ['foo', 'bar']) {
console.log(x);
}
}
main();
And we get the same results logged.
Async Generators
Async generators let us create async iterable.
An async generator is just a generator function that returns promises.
For instance, we can create an async generator function by writing:
async function* createAsyncIterable(arr) {
for (const elem of arr) {
yield elem;
}
}
A normal generator returns a generator object.
And each invocation of the next
method returns an object with the properties value
and done
.
And an async generator returns a generator object.
Each next
call returns a promise for an object with properties value
and done
.
When we call an async generator, the JavaScript engine will wait for the promise to be settled before calling the next one.
Every async generator has a queue with promises to be settled with yield
or throw
.
And when next
is called, a promise is queued.
And unless the async generator is already running, it resumes and waits for the promise to be finished.
It can finish with yield
, throw
or return await
.
Once it’s finished the promise is returned.
The result of a settled promise is delivered in an async manner.
Conclusion
The for-await-of loop lets us iterate through async generators by returning promises of each value sequentially.