DEV Community

Discussion on: Async/Await and the forEach Pit of Despair

Collapse
 
qm3ster profile image
Mihail Malo • Edited

You need to be aware that you not only changed the order of the output, but also limited concurrent requests from "all at once" to "only ONE at a time" which is not what you'd often want.
If you wanted to log them asynchronously, but in the returned order, you only had to make a small change:

ConsoleLogHTML.connect(document.getElementById('log'));

const baseURL = 'https://jsonplaceholder.typicode.com';

async function main() {
  // get all posts
  const posts = await axios(`${baseURL}/posts`);
  const names = posts.data.map(async (post, index) => {
    // get the user who posted this post
    const user = await axios(`${baseURL}/users/${post.userId}`);
    return `${index}: ${user.data.name}`;
  });
  for (const name of names) {
    console.log(await name)
  }
}

main();

This way, all requests are started at the beginning, and then we go through the list of promises in order, effectively sleeping on every unfinished request.
Usually, in a situation like that I won't splurge for an inner async function, so it would actually end up looking like this:

ConsoleLogHTML.connect(document.getElementById('log'))

const baseURL = 'https://jsonplaceholder.typicode.com'

async function main() {
  // get all posts
  const posts = await axios(`${baseURL}/posts`)
  // map user ids to user name promises
  const names = posts.data.map((post, index) =>
    axios(`${baseURL}/users/${post.userId}`).then(
      user => `${index}: ${user.data.name}`
    )
  )
  for (const name of names) {
    console.log(await name)
  }
}

main()

No brakes on the ajax train

If you truly wanted to display them asynchronously, and as soon as possible, you'd reserve space for each request's output, like this:

All at once (feat. Promise.all)

Finally, if you only care about all the data together, and don't need it to get in front of the user's eyes as soon as humanly possible, just use Promise.all:

ConsoleLogHTML.connect(document.getElementById('log'))

const baseURL = 'https://jsonplaceholder.typicode.com'

async function main() {
  // get all posts
  let posts = await axios(`${baseURL}/posts`)
  const users = await Promise.all(
    posts.data.map(post => axios(`${baseURL}/users/${post.userId}`))
  )
  for (const user of users) {
    console.log(`${users.indexOf(user)}: ${user.data.name}`)
  }
}

main()