DEV Community

Norman
Norman

Posted on

Javascripts async and loops

Thanks to async/await many pieces of code became much more declarative. But there is one tricky scenario that I just bumped into: I needed to do a handful of API requests in a loop and refresh the list view afterwards. Easy peasy?

async updateAllItems (listOfItems) {
  listOfItems.forEach(async (item) => {
    await collection.updateItem(item.id, { status: 'coolNewStatus' })
  })
  const newItems = await collection.allItems()
  return newItems
}
Enter fullscreen mode Exit fullscreen mode

What's the problem here? Some people might have seen it already (unlike me in the last couple of hours): newItems will be loaded before the loop ended because we're not actually waiting for it to end. Simply throwing another await in front of it doesn't cut it either.

There are at least three possible solutions, depending on your style.

✅ Sticking to the procedural approach:

async updateAllItems (listOfItems) {
  for (const item of listOfItems) {
    await collection.updateItem(item.id, { status: 'coolNewStatus' })
  }
  const newItems = await collection.allItems()
  return newItems
}
Enter fullscreen mode Exit fullscreen mode

Why are people so afraid of for-loops anyway?

✅ Promise.all

async updateAllItems (listOfItems) {
  await Promise.all(listOfItems.map(item => {
    return collection.updateItem(item.id, { status: 'coolNewStatus' })
  }))
  const newItems = await collection.allItems()
  return newItems
}
Enter fullscreen mode Exit fullscreen mode

A little lispy, isn't it?

❌ await async

async updateAllItems (listOfItems) {
  listOfItems.forEach(await (async (item) => {
    await collection.updateItem(item.id, { status: 'coolNewStatus' })
  }))
  const newItems = await collection.allItems()
  return newItems
}
Enter fullscreen mode Exit fullscreen mode

This does NOT work. Why? No idea. Do you have any idea?

Anyways, I hope this helps you with your next async race condition. Cheers 🥂

Latest comments (0)