JavaScript: What You Should Not Do with async/await
NicolasBrondinBernard
Using async/await is great, except in certain cases!

Article published on 04/06/2021, last updated on 10/08/2026
Before continuing: reading this article requires understanding what the async and await keywords are in ES6, as well as how to use them.
If that's not the case, I invite you to read this tutorial on the javascript.info website!
As a reminder: async allows a function to return a promise, while the await keyword allows you to wait for a promise to resolve in a synchronous (or blocking) manner and retrieve the returned value directly into a variable.
In practice, promises are used to avoid callback hell, and async/await allow you to avoid stacking up thens all over the place!
But the trap of this technology lies in the fact that synchronous code is much easier for a developer to read, but it can also be far less performant than asynchronous code, which sometimes leads to poor usage.
Example
Let's take a function that will simulate some kind of asynchronous call (API, database, etc...) using a simple one-second timeout:
function t(){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve();
},1000);
})
}
We can then call this function and wait for its return synchronously using await like this:
...
console.time();
await t();
console.timeEnd();
...
The console will tell us that execution finished in a little over 1 second, which corresponds to the script's execution time, including the resolution of the promise and the blocking caused by await.
So far so good.
If you're not familiar with the console.time() method, I invite you to read my dedicated article on the console API methods worth knowing.
What not to do
Let's imagine we now need to make several calls to our API, and wait for all of these calls to finish before continuing the execution of our code.
We might then be tempted to write code like this:
...
for(let i=0 ; i<25 ; i++){
await t();
}
...
And there, horror, our entire script will take a bit more than 25 seconds to run! Yes, because even though our machine (or our API) would have been capable of handling all these calls in parallel, we forced our script to wait for each promise to return before making a new call.
This code, although easily readable and understandable by a developer (because it's written in a "synchronous" way) actually breaks all the advantages of Javascript, which is a language based on an event loop and asynchronous by nature!
This demonstration was carried out by a professional, do not try this at home.
The solution
There is a method that easily solves this problem and keeps both the readability of the code and its performance.
This method is called Promise.all(...); it takes as a parameter an array of promises awaiting resolution and will itself return a new promise only once all the promises contained in the array passed as a parameter have been resolved.
Here is the equivalent of the previous loop in the example below:
...
const promises = [];
for(let i=0 ; i<25 ; i++){
promises.push(t()); //non-blocking execution
}
await Promise.all(promises);
...
As you can see, every time we call the t() method, we store the returned promise in an array.
All the calls to the function can therefore be made in parallel, but the rest of our code will only run once all the promises have been resolved, just like before.
Result: the execution of the script and the 25 calls takes 1.024s, which is 25 times less time than with the previous solution.
Obviously in a real-world case, the final execution time will depend on the ability of the asynchronous service (here replaced by the timeout) to handle concurrent requests, but the performance will always be incomparable when using Promise.all!
I invite you to read the official documentation for this method on the Mozilla Developer Network documentation!
Additionally, Promise.all(...) returns a promise obviously containing the array of data returned by each resolved promise, in the exact order the calls were made, so there's no problem retrieving all your data!
Conclusion
If you're making asynchronous calls in a loop and waiting for all the calls to finish, use Promise.all instead of making your code completely synchronous with async/await!
Complete courses, exercises and certificates to really learn programming!
4.8 average rating
No comments yet