Master Async Operations with Promise.allSettled in JavaScript

Published on | Reading time: 7 min | Author: Andrés Reyes Galgani

Master Async Operations with Promise.allSettled in JavaScript
Photo courtesy of Firmbee.com

Table of Contents

  1. Introduction
  2. Problem Explanation
  3. Solution with Code Snippet
  4. Practical Application
  5. Potential Drawbacks and Considerations
  6. Conclusion
  7. Final Thoughts
  8. Further Reading

Introduction 🚀

Imagine it’s a typical day in your development life. You’re navigating the complex labyrinth of your application, dealing with various data manipulations and transformations. Suddenly, you encounter a formidable nemesis: the notorious callback hell! The tangled web of nested callbacks feels like a programming rite of passage gone wrong. You’ve probably experienced this more times than you’d like to remember, and the dread of flattening your callback structure looms large.

Wouldn't it be fantastic if you could simplify this mess and embrace a cleaner, more efficient way to handle asynchronous operations? Enter async/await in JavaScript, a feature that has revolutionized how we write asynchronous code. It offers a much more intuitive and readable syntax compared to traditional promise chaining and callbacks. But there’s a lesser-known trick that can make this transformation even smoother—introducing the Promise.allSettled() method, which allows developers to handle multiple promises with grace.

This post aims to provide a closer look at how Promise.allSettled() can be your secret weapon when dealing with a multitude of asynchronous operations. You’ll see how to use it to keep your code clean, even when things get messy, and prevent your mental faculties from breaking down under the pressure. So, grab your coffee, and let’s dive into these powerful features!


Problem Explanation 🔍

As the complexity of JavaScript applications grows, handling multiple asynchronous operations often leads developers down the dreaded callback hell path. Nesting callbacks can make code harder to read and maintain, leading to what many refer to as “pyramid of doom” situations. This is where functions upon functions are wrapped in each other, creating deep nesting levels that can turn even the simplest task into an unreadable mess.

Consider the conventional approach using promises. When multiple asynchronous calls need to be made, you might find your code starting to look something like this:

function fetchData() {
    fetch('/api/data1')
        .then(response => response.json())
        .then(data1 => {
            fetch('/api/data2')
                .then(response => response.json())
                .then(data2 => {
                    fetch('/api/data3')
                        .then(response => response.json())
                        .then(data3 => {
                            // Process data
                        })
                        .catch(err => console.error(err));
                })
                .catch(err => console.error(err));
        })
        .catch(err => console.error(err));
}

With the above approach, you can see the daunting amount of nesting. This makes the errors harder to catch and the success path convoluted. The code gets less readable and harder to debug, blocking you from using the full features of modern JavaScript effectively. Naturally, you might wonder if there is a better way.


Solution with Code Snippet ✨

Enter async/await! By using these keywords, you can write cleaner and more understandable code. Combined with Promise.allSettled(), which waits for all promises to settle (either fulfilled or rejected), you can create a scenario where multiple API calls are managed without the dreaded nesting, allowing for better error handling while still maintaining a linear flow of logic.

Let’s revisit the earlier code with this approach:

async function fetchAllData() {
    try {
        // Initiate all API calls
        const responses = await Promise.allSettled([
            fetch('/api/data1'),
            fetch('/api/data2'),
            fetch('/api/data3')
        ]);

        // Process results
        const results = responses.map(response => {
            // Handle result
            if (response.status === 'fulfilled') {
                return response.value.json();
            } else {
                console.error(`Error fetching: ${response.reason}`);
                return null; // or handle accordingly
            }
        });

        // Wait for all resolved promises
        const data = await Promise.all(results);
        // Process final data, e.g., render in UI

    } catch (error) {
        console.error('An unexpected error occurred', error);
    }
}

Explanation:

  1. Promise.allSettled: This method accepts an iterable of promises and returns a single Promise that resolves when all of the promises have either resolved or rejected, with an array of objects that each describe the outcome of each promise.

  2. Handling Results: The map function is used to process each response. If a call was fulfilled, its JSON data can be accessed; if it was rejected, it’s logged without breaking the flow.

  3. Linear Logic Flow: This approach makes it easy to read and understand the execution order, reducing complex nesting and improving maintainability.

By adopting this pattern, you not only improve readability but also leverage better error handling for each individual API call.


Practical Application 🛠️

The Promise.allSettled() method is particularly useful in scenarios where you need to make multiple independent API requests, such as fetching user data, notifications, and statistics simultaneously. Instead of waiting for one to finish before starting another, you can initiate all requests at once and gather their results once they settle—ideal for dashboard applications or admin panels.

For example, when building a dashboard that aggregates data from various services, implementing the async/await pattern combined with Promise.allSettled() can save you from excessive wait times and enhance the user experience.

Integration Example:

Imagine you are building a user dashboard where you fetch user profiles, statistics, and recent activity simultaneously. Using the above method, you can present a loading state while waiting for all data to arrive, allowing users to see updates quicker and providing a smoother feel to the application.


Potential Drawbacks and Considerations ⚠️

While Promise.allSettled() is undoubtedly powerful, there are scenarios where it may not be the ideal solution. For instance, if you require that all operations succeed for the next step to proceed (for example, all CRUD operations successfully completing on a batch update), then using Promise.all() would be a better fit. If any promise rejects in Promise.all(), the entire batch will be rejected, halting further processing.

Moreover, it’s good practice to ensure that not processing rejected promises doesn’t lead to silent failures. Always include error logging or handling mechanisms to catch potentially unnoticed issues.

To mitigate these drawbacks, always assess whether your operation’s logic allows for failures before opting for Promise.allSettled(). Review the specific needs of your application's workflows to choose the best handling approach for your concurrent tasks.


Conclusion 🎉

In summary, the combination of async/await with Promise.allSettled() provides an elegant solution to manage multiple asynchronous operations without falling into the pitfalls of callback hell. You’ll find that embracing this pattern significantly enhances your code's readability, maintainability, and error handling prospect while allowing for simultaneously executing tasks.

The ease of writing cleaner code that still handles errors gracefully positions this approach as a best practice in modern JavaScript development.


Final Thoughts 💭

I encourage you to experiment with implementing Promise.allSettled() in your applications. Whether you’re refactoring legacy code or building new features, the benefits to your flow will soon become apparent. Please share your experiences or alternative async handling methods in the comments below.

And don’t forget to subscribe for more tech insights and tips aimed at transforming your coding adventures!


Further Reading 📚

Focus Keyword: Promise.allSettled
Related Keywords: Async/Await, JavaScript Promises, Callbacks, Error Handling, Asynchronous Operations