One of the ES6 features that made a lot of impact are iterators. They allow the spread operator to work, make a lot of commonly used Array functions possible, and even a simple for-of loop uses them internally.
Ever since ES6 it's possible to create your own iterables by implementing an iterator for it.
Up until now, all iteration had happened synchronously. But what would you do if you needed to read lines asynchronously from a file?
ES2018 introduced a feature to allow for this: asynchronous iteration. You can create custom async iterables by using the [Symbol.asyncIterator] syntax. It works exactly like the [Symbol.iterator] syntax, except the next() method doesn't return {value, done} tuples directly. it returns Promises that resolve into those tuples.
With the use of async generators, it becomes even easier:
async function* generator() {
yield 1;
yield 2;
yield 3;
yield 4;
}
(async function () {
for await (const el of generator()) {
console.log(el);
}
})();
Using the for-await-of syntax, you can loop over your asynchronous iterables, and it works just as well on synchronous iterables.