for-await-of and synchronous iterables

December 16, 2017 0 Comments

for-await-of and synchronous iterables

 

 

This blog post describes how for-await-of handles synchronous iterables. for-await-of is a core construct of asynchronous iteration. You can read up on it in the blog post “ES proposal: asynchronous iteration”.

Note: you can run the examples in Node.js 9.2+ via:

node --harmony-async-iteration

Refresher: asynchronous iterables  #

Asynchronous iterables return asynchronous iterators, whose method next() returns Promises for {value, done} objects:


async function* asyncGen() { yield 'a'; yield 'b';
}
const iter = asyncGen()[Symbol.asyncIterator](); iter.next().then(x => console.log(x)); iter.next().then(x => console.log(x)); iter.next().then(x => console.log(x)); 

Synchronous iterables and for-await-of  #

Synchronous iterables return synchronous iterators, whose method next() returns {value, done} objects. for-await-of handles synchronous iterables by converting them to asynchronous iterables. Each iterated value is converted to a Promise (or left unchanged if it already is a Promise) via Promise.resolve(). That is, for-await-of works for iterables over Promises and over normal values. The conversion looks like this:

const nextResult = Promise.resolve(valueOrPromise) .then(x => ({ value: x, done: false }));

Two more ways of looking at the conversion are:

  • Iterable<Promise<T>> becomes AsyncIterable<T>

  • The following object

    { value: Promise.resolve(123), done: false }
    

    is converted to

    Promise.resolve({ value: 123, done: false })
    

Therefore, the following two statements are roughly similar.

for (const x of await Promise.all(syncIterableOverPromises));
for await (const x of syncIterableOverPromises);

The second statement is faster, because Promise.all() only creates the Promise for the Array after all Promises in syncIterableOverPromises are fulfilled. And for-of has to await that Promise. In contrast, for-await-of starts processing as soon as the first Promise is fulfilled.

for-await-of in action  #

Iterating over a sync iterable over Promises:

async function main() { const syncIterable = [ Promise.resolve('a'), Promise.resolve('b'), ]; for await (const x of syncIterable) { console.log(x); }
}
main(); 

Iterating over a sync iterable over normal values:

async function main() { for await (const x of ['c', 'd']) { console.log(x); }
}
main(); 

Further reading  #


Tag cloud