AppDividend
Latest Code Tutorials

The Definitive Guide on Javascript Promise.all()

0

Javascript Promise all() is an inbuilt function that returns the single Promise that resolves when all of the promises passed as the iterable have resolved or when an iterable contains no promises.  The Promise .all() function can be useful for aggregating the results of the multiple promises. The Promise all() rejects with the reason of the first Promise that rejects or with the error caught by the first argument if that argument has caught the error inside it using try/catch/throw blocks.

Promise.all takes the Async operations to the next new level as it helps you to aggregate the group of promises. In other words, we can say that it helps you to do concurrent operations.

Javascript Promise all example

Promises in JavaScript are one of the robust APIs that help us to do the Async operations.

Promise all() method rejects with a reason for the first Promise that rejects. There is no particular ordering in the execution of an array of Promises given.

On some computer systems, they may be executed in parallel or some sense concurrently, while on the other systems, they may be executed serially.

For this unpredictable behavior of promises, there must be no dependency on any Promise on the order of execution of the Promises.

For instance, assume that you have eleven(11) promises (Async operation to perform a network call or the database connection).

In this case, you have to know when all the promises get resolved or wait until all the promises resolve.

So you are passing all ten promises to Promise .all. Then, Promise.all() itself as a promise will get resolved once all the ten promises get resolved, or any of the ten promises get rejected with an error.

If any of the passed-in promises reject, a Promise.all() function asynchronously rejects the value of a promise that rejected, independent of what other promises have resolved or not. It has nothing to do with that.

Syntax

Promise.all(iterable);

Parameters

An iterable parameter is an object such as an Array or String.

Return Value

Javascript Promise all() function returns one of the following values.

  1. An already resolved Promise if an iterable passed is empty.
  2. An asynchronously resolved Promise if an iterable passed contains no promises.
  3. The pending Promise in all other cases. It returned Promise is then resolved/rejected asynchronously (as soon as the stack is empty) when all the promises in the given iterable have resolved, or if any of the promises reject. Returned values will be in the order of the Promises passed, regardless of the complete order.

Promise.all is a promise that takes an array of promises as an input (an iterable). Then it gets resolved when all the promises get resolved, or anyone of them gets rejected.

Let us take a simple example. Let us create one file called app.js and write the following code.

// app.js

const p1 = Promise.resolve(21);
const p2 = 110470116021;
const p3 = new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
	setTimeout(() => {
		resolve('AppDividend');
	}, 1000);
});

Promise.all([p1, p2, p3]).then(values => { 
	console.log(values);
});

Here, we have defined the three promises. Then we have set the Promise all() method to return a single promise based on three promises. In this example, all of the three promises resolves so, the Promise.all() function resolves and gives the output of all three promises in the form of an array.

The output is the following. I am using Node.js to run the file by typing the node app.

Javascript Promise All Example | Promise.all() Tutorial

Rejecting Promise.all() in Javascript

If you create three promises and two Promise resolved but one rejects then promise.all() method will reject the Promise. If we want many promises to execute in parallel and wait until all of them are ready, then the Promise .all() is useful because if one of them will fail, then it rejects the whole Promise.

One thing to note here that the order of the resulting array members is the same as in its source promises. Even though the first Promise takes the longest time to resolve, it still appears first in the array of results.

If one Promise rejects, Promise.all immediately reject, completely forgetting about the other ones on the list. Their results are ignored.

Behind the scenes, what is happening is that if one promise fails, the others will continue to execute, but Promise.all() won’t watch them anymore. They will probably conclude, but their results will be ignored.

Let us take a scenario where one of the above promises fails to resolve.

// app.js

const p1 = Promise.resolve(21);
const p2 = new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
	setTimeout(() => {
		reject(new Error('rejection'));
	}, 1000);
});
const p3 = new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
	setTimeout(() => {
		resolve('AppDividend');
	}, 1000);
});

Promise.all([p1, p2, p3]).then(values => { 
	console.log(values);
});

In the above example, the second Promise is rejected; that is why the final output will be throwing an error.

Promise.all() rejects scenario

The Promise .all()  is rejected if any of the elements are rejected. For example, if you pass in four promises that resolve after a timeout and one Promise that rejects immediately, then Promise.all() will reject immediately.

See, we get an error like this because we have rejected one Promise, and the final Promise will also be rejected.

It is possible to change this practice by handling possible rejections.

// app.js

const p1 = Promise.resolve(21);
const p2 = new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
	setTimeout(() => {
		reject(new Error('rejection'));
	}, 1000);
});
const p3 = new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
	setTimeout(() => {
		resolve('AppDividend');
	}, 1000);
});

Promise.all([
	p1.catch(error => { return error; }),
	p2.catch(error => { return error; }),
	p3.catch(error => { return error; }),
]).then(values => {
	console.log(values[0]);
	console.log(values[1]);
	console.log(values[2]);
});

In the above example, we are catching those errors inside the all() block, if any promises reject with an error, and then display the values of each Promise. The output is the following.

Javascript Promise All Example

If one of the promises reject, Promise.all() immediately reject, completely forgetting about the other ones on the list. Their results are ignored.

For example, if there are multiple AJAX calls, and one fails, other ones will continue to execute, but Promise.all() won’t watch them anymore. They will probably settle, but the result will be ignored.

Promise.all does nothing to cancel them, as there’s no concept of “cancellation” in promises.

The Promise .all() method is good for “all or nothing” cases.

Use cases of Promise .all() in Javascript

Assume that you have to perform a huge number of Async operations like sending bulk push notification to thousands of subscribers.

Simple pseudocode would be the following.

for (let x = 0;x < 50000; x += 1) {
 sendPushNotificationForUser(user[x]) // Async operation to send a push notification
}

The above example is simple, but it’s not very performant.

The stack will become too heavy, and at one point of time, JavaScript will have a huge number of open HTTP connection which may kill the server.

A simple, performant approach would be to do it in batches. Take the first 500 users, trigger the push notification, and wait till all the HTTP connections are closed. And then take the next batch to process it and so on.

See the following code.

const sendNotificationForUsers = async (users) => {
  const usersLength = users.length

  for (let i = 0; i < usersLength; i += 100) {
    const requests = users.slice(i, i + 100).map((user) => { // The batch size is 100. We are processing in a set of 100 users.
      return triggerNotificationForUser(user) // Async function to send the mail.
        .catch(e => console.log(`Error in sending notification for ${user} - ${e}`)) // Catch the error if something goes wrong. So that it won't block the loop.
    })

    // requests will have 100 or less pending promises. 
    // Promise.all will wait till all the promises got resolves and then take the next 100.
    await Promise.all(requests)
      .catch(e => console.log(`Error in sending notification for the batch ${i} - ${e}`)) // Catch the error.
  }
}

sendNotificationForUsers(userLists)

 So, this is how you send the notification in batches.

Conclusion

Javascript Promise all is the best way to aggregate a group of promises to a single promise. This is one of the ways of achieving concurrency in JavaScript.

The returned Promise is fulfilled with an array containing all the values of the iterable passed as argument (also non-promise values).

  1. If an empty iterable is passed, then this method returns (synchronously) an already resolved promise.
  2. If all of the passed-in promises fulfill or are not promises, the Promise returned by Promise .all is fulfilled asynchronously.

If any of the passed-in promises reject, Promise.all() asynchronously rejects the value of the Promise that rejected, whether or not the other promises have resolved.

The key aspect of promises is that they’re a pipeline, and the various handlers can massage the data in the pipeline.

For more information about the Promise, you can read an article on the Mozilla docs.

Wrapping Up

There are five static methods of Promise class:

Promise.all(promises) – The function waits for all promises to resolve and returns the array of their results. If any of the given promises rejects, it becomes an error of the Promise.all() method and all other results are ignored.

Promise.allSettled(promises) (recently added method) – The allSettled() function waits for all promises to conclude and returns their results as the array of objects with:

state: “fulfilled” or “rejected”
value (if fulfilled) or reason (if rejected).

Promise.race(promises) – The race() function waits for the first Promise to settle, and its result/error becomes the outcome.

Promise.resolve(value) – The resolve() function makes a resolved promise with the given value.

Promise.reject(error) – The reject() function makes a rejected promise with the given error.

That is it for Javascript Promise.all() method.

Recommended Posts

Promise.resolve()

Promise.reject()

Promise.race()

Javascript async / await

Node Async Await

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.