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;
}
}
}