Is there any difference between this:
const promises = await Promise.all(items.map(e => somethingAsync(e))); for (const res of promises) { // do some calculations }
And this ?
for await (const res of items.map(e => somethingAsync(e))) { // do some calculations }
I know that in the first snippet, all the promises are fired at the same time but I'm not sure about the second. Does the for loop wait for the first iteration to be done to call the next promise ? Or are all the promises fired at the same time and the inside of the loop acts like a callback for them ?
The most important difference is that Promise. all() handles its input promises concurrently, while for await...of resolves them one at the time.
Async/Await is used to work with promises in asynchronous functions. It is basically syntactic sugar for promises. It is just a wrapper to restyle code and make promises easier to read and use. It makes asynchronous code look more like synchronous/procedural code, which is easier to understand.
This rule applies when the await operator is used on a non-Promise value. await operator pauses the execution of the current async function until the operand Promise is resolved.
Promise.all waits for all fulfillments (or the first rejection).
Yes, they absolutely are different. for await
is supposed to be used with asynchronous iterators, not with arrays of pre-existing promises.
Just to make clear,
for await (const res of items.map(e => somethingAsync(e))) …
works the same as
const promises = items.map(e => somethingAsync(e)); for await (const res of promises) …
or
const promises = [somethingAsync(items[0]), somethingAsync(items[1]), …]; for await (const res of promises) …
The somethingAsync
calls are happening immediately, all at once, before anything is awaited. Then, they are await
ed one after another, which is definitely a problem if any one of them gets rejected: it will cause an unhandled promise rejection error. Using Promise.all
is the only viable choice to deal with the array of promises:
for (const res of await Promise.all(promises)) …
See Waiting for more than one concurrent await operation and Any difference between await Promise.all() and multiple await? for details.
The need for for await ...
arises when on an asynchronous iterator the computation of the current iteration depends on some of the previous iterations. If there are no dependences, Promise.all
is your choice. The for await
construct was designed to work with asynchronous iterators, although - as in your example, you can use it with an array of promises.
See the example paginated data in the book javascript.info for an example using an asynchronous iterator that can't be rewritten using Promise.all
:
(async () => { for await (const commit of fetchCommits('javascript-tutorial/en.javascript.info')) { console.log(commit.author.login); } })();
Here the fetchCommits
async iterator makes a request to fetch
the commits of a GitHub repo. The fetch
responds with a JSON of 30 commits, and also provides a link to the next page in the Link
header. Therefore the next iteration can only start after the previous iteration has the link for the next request
async function* fetchCommits(repo) { let url = `https://api.github.com/repos/${repo}/commits`; while (url) { const response = await fetch(url, { headers: {'User-Agent': 'Our script'}, }); const body = await response.json(); // (array of commits // The URL of the next page is in the headers, extract it using a regexp let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/); nextPage = nextPage?.[1]; url = nextPage; for(let commit of body) { // yield commits one by one, until the page ends yield commit; } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With