Avoid await in Loops: Clean Async Patterns with Promise.all

During my work with ESLint in projects, I wanted to take full advantage of its rules to ensure my code is well-constructed.
One of the rules I noticed is called no-await-in-loop
.
This rule states that you should avoid using the await
keyword in loops like for
and while
.
However, there are situations where we need to make asynchronous calls inside loops, such as deleting order items after deleting an order, or deleting user images after deleting a user from the database, and so on.
For this reason, we should find a way to refactor this pattern.
#The Solution
The solution to this problem is quite simple. To apply it, we will use two concepts in JavaScript:
Promise.all()
method from the Promise objectArray.map()
method from the Array object
#Hands-On Example
Below is an example of deleting all user images from the user_images
table in the database after deleting a user from the users
table. We initially used a for-of
loop to delete each image from the table:
async function deleteUser(userId: string) { // Delete the user from the database await deleteUserFromDB(userId);
// Get user images from the database const userImages = await getUserImages(userId);
// Loop through each image and delete it for (const image of userImages) { await deleteUserImage(image.id); }
console.log("User and their images have been deleted.");}
#Refactored Code
Now let’s refactor this code to comply with the ESLint rule:
async function deleteUser(userId: string) { // Delete the user from the database await deleteUserFromDB(userId);
// Get user images from the database const userImages = await getUserImages(userId);
// Use map to create an array of promises without awaiting in the loop const deleteImagePromises = userImages.map((image) => deleteUserImage(image.id), );
// Execute all promises concurrently await Promise.all(deleteImagePromises);
console.log("User and their images have been deleted.");}
In the refactored code:
We extract the loop logic into the map function, where we call the deleteUserImage()
method without the await keyword. This returns an array of promises. Afterward, we use the Promise.all()
method on the array of promises to execute all asynchronous function calls concurrently.
I hope you enjoyed this tutorial and found it helpful. Following ESLint rules can improve code quality and make it more predictable and clean.