In the previous lesson, we learned about promise chaining and how it can be used to handle sequential asynchronous tasks. However, there are scenarios where multiple asynchronous operations are independent and can be executed concurrently.
In some situations, it is crucial that all operations succeed for the application to proceed, such as loading data for a dashboard. In other cases, while the tasks can run concurrently, maintaining the order of results regardless of the completion times is essential for proper functionality.
The Promise.all
method provides a solution to make sure all tasks succeed together and maintain the order of results as needed.
Let us look at an example to understand the use-case better.
User Dashboard
Imagine you are building a user dashboard for an application. To display the dashboard, you need to fetch the user’s profile, recent activity, and notification settings. These operations are independent, meaning they can execute concurrently. However, the dashboard cannot render until all the data is successfully fetched. If even one of the operations fails, the entire process should fail, and an error should be handled.
In the above code, the logs appear in a different order because the promises resolve at different times based on their setTimeout
delays. For example, the Recent Activity log may appear before the User Profile log.
Also, as the causeErrorWhilefetchingNotificationSetting
is set to false, the fetchNotificationSettings
rejects with an error. However, since each promise is handled separately, the program does not stop or handle this failure collectively. Instead, it continues to log the other results, leading to incomplete and potentially misleading data on the dashboard.
To make sure that all tasks are completed before processing the data, and to maintain the order of the promises, we use Promise.all
. This method takes an array of promises and returns a single promise. The promise returned by this method resolves when all the promises in the array are resolved. The resolved values are returned as an array, preserving the order of the promises passed, regardless of the order in which the promises complete.
However, if any one of the promises is rejected, Promise.all
stops immediately and rejects with the reason of the first rejected promise. This makes it an ideal choice when all tasks need to succeed to move forward, and failure in even one task should halt the process.
Let us see how we can achieve this using Promise.all
.
In the above code, if all three promises resolve successfully, the .then()
block runs, logging the fetched data and confirming the successful dashboard loading. The resolved values are returned as an array in the order of the promises passed to Promise.all
, regardless of the order in which the promises complete.
Promise.all
stops as soon as the first promise rejects, and the rejection reason is passed to the .catch()
block.
To test this behavior, try changing the boolean values of causeErrorWhilefetchingUserProfile
, causeErrorWhilefetchingRecentActivity
, or causeErrorWhilefetchingNotificationSetting
to false
. This will create an error in the corresponding operation. Observe how the error halts the entire process and makes sure that no further tasks are processed, demonstrating that Promise.all
requires all tasks to succeed for the overall operation to proceed.