DEV Community

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

Collapse
 
dipunm profile image
Dipun Mistry

Everything you describe from a code point of view is correct, but as a developer, when you write code, you should know what you are writing. Let's talk about await async first:

async function main() {
    await somethingAsync();
    return 20;
}

function main2() {
    return somethingAsync().then(_ => 20);
}

The two methods above are identical. This is what is happening behind the scenes.

now a quick primer on forEach:

myArray.forEach(function(val) {
  return val + 20;
});

most people know that returning something here is pointless, forEach will run your function for every item in the array, but it won't do anything with what you return.

Let's go back to await async:

async function main() {
  await doSomethingAsync();
}

Although this doesn't look like it returns anything, it actually translates to this:

function main() {
  return doSomethingAsync();
}

This is why you need to await on async functions and just like in any language, the async/await paradigm bleeds out and suddenly everything is asynchronous. If you don't await on that function when you call it, you risk running your next operation before the first operation finished.

In some cases this is fine, sometimes you want your application to go off and do a bunch of things at once, eg: when a page loads in the browser, you want the browser to go fetch your images, js and css as quickly as possible, making use of all it's resources; you don't want it to fetch them one at a time.

Now remember, forEach does nothing with whatever you return in your function, but async functions need to be awaited if you want things to go in sequencial order.

Looking at your example, you might actually be missing a trick: just because the console logs need to run sequentially, doesn't mean you should force your http calls to happen sequentially:

const p_users = data.map((post, index) => axios(post, index));
const users = await Promise.all(p_users); // Promise.all maintains the order of values, and waits for all promises to resolve before continuing.
users.forEach(user => console.log(user));

The above call will allow you to make all your http calls at the same time instead of one at a time but allows you to log your messages in the correct order. Overall, same result, just faster.

Everything you saw happen, happened by design; this may be an insightful article for the next developer, but let's educate and empower without scaring and blaming.