JavaScript Promise: .all() vs .allSettled() and .race() vs .any()
Tags: webdev, javascript, react, node
Published: 2023-08-26 19:06:17

In previous articles we learned about [how Promise work](https://dev.to/shameel/understanding-promise-in-javascript-45kc) and discussed about `then` `catch` and `finally` methods.

Today we will be discussing:

1. [Promise.all()](#promiseall-section)
2. [Promise.allSettled()](#promiseallSettled-section)
3. [Difference + Usecase of Promise.all() and Promise.allSettled()](#difference1)
4. [Promise.race()](#promiserace-section)
5. [Promise.any()](#promiseany-section)
6. [Difference + Usecase of Promise.race() and Promise.any()](#difference2)

All these methods take `array of promises` as an `input` but deals differently with respect to their behavior.

By mastering these methods, you'll have a versatile toolkit at your disposal, which will allow you to manage complex asynchronous operations.

## Promise.all() <a name="promiseall-section"></a>

`Promise.all` method in JavaScript is used to handle multiple promises concurrently and wait for all of them to resolve.

**ALL PROMISES MUST BE RESOLVED FOR IT TO RETURN A RESPONSE**. Never forget that. =)

If all promises resolve then it returns an array with all resolved promises.

Let's take an example with the code:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.all(promisesArray)
  .then((results) => {
    console.log("All promises resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```
In this snippet, we have three promises which resolve after `500`, `800` and `1000` milliseconds. Since all of them are going to be resolved so you will see the log like this after you run this snippet:
```
All promises resolved: [ 'Promise 1 resolved', 'Promise 2 resolved', 'Promise 3 resolved' ]
```

If any of the promise rejects, it won't wait for others to resolve and will return with reason of the promise that is rejected. Look at example below to get the better idea about this:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((_, reject) =>
  setTimeout(() => reject("Promise 3 rejected"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.all(promisesArray)
  .then((results) => {
    console.log("All promises resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```

Here, `promise2` resolves after `500` seconds but `promise3` rejects after `800` seconds so it will not wait for `promise1` and will return a response:

```
At least one promise rejected: Promise 3 rejected
```

## Promise.allSettled() <a name="promiseallSettled-section"></a>

The `Promise.allSettled` method is used to handle multiple promises concurrently, just like `Promise.all`, but it waits for all the promises to settle (either resolve or reject) before proceeding. It returns an array of objects representing the outcomes of the input promises, including their values or reasons for rejection.

`Promise.allSettled()` always returns `array of objects` with `status` key which denotes `fulfilled` or `rejected`. If a promise is `fulfilled` then you can get response with `value` key and if the promise is rejected then you can find the reason in `reason` key.

Look at this code:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.allSettled(promisesArray).then((results) => {
  console.log("All promises settled:", results);
});
```

You will see a response like this:
```
[
  { status: 'fulfilled', value: 'Promise 1 resolved' },
  { status: 'fulfilled', value: 'Promise 2 resolved' },
  { status: 'fulfilled', value: 'Promise 3 resolved' }
]
```
Now we will try and reject `promise2` like we did previously and see the response:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_, reject) =>
  setTimeout(() => reject("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.allSettled(promisesArray).then((results) => {
  console.log("All promises settled:", results);
});
```

Response:
```
[
  { status: 'fulfilled', value: 'Promise 1 resolved' },
  { status: 'rejected', reason: 'Promise 2 resolved' },
  { status: 'fulfilled', value: 'Promise 3 resolved' }
]
```
## Difference between Promise.all() and Promise.allSettled() <a name="difference1"></a>
We have uncovered the difference of these two already with the coding approach; lets further theoretically discuss these

The `Promise.all` and `Promise.allSettled` methods are both used to work with multiple promises, but they have different behaviors when it comes to handling resolved and rejected promises. Here are the key differences between the two methods:

### Handling Rejected Promises:

**Promise.all**: If any of the input promises is rejected, the entire returned promise will immediately reject with the reason of the first rejected promise. The resolution of `Promise.all` depends on all promises being fulfilled successfully.

**Promise.allSettled**: The returned promise always resolves, regardless of whether individual promises were fulfilled or rejected. The result is an array of objects representing the outcomes of all input promises, including both fulfilled and rejected ones.

### Resolution Behavior:

**Promise.all**: Resolves only if all input promises are resolved successfully. The resolved value is an array containing the resolved values of the input promises in the same order.

**Promise.allSettled**: Resolves with an array of objects, one for each input promise. These objects contain the status of each promise ("fulfilled" or "rejected") along with the value (if resolved) or reason (if rejected).

### Use Cases:

**Promise.all**: Useful when you want to wait for multiple asynchronous operations to complete and need all of them to be successful before proceeding. For example, making multiple API requests in parallel and waiting for all responses.

**Promise.allSettled**: Useful when you want to gather the results of multiple asynchronous operations, regardless of whether they succeeded or failed. It's often used when you want to know the outcome of all promises, even if some of them are rejected.



## Promise.race() <a name="promiserace-section"></a>

As the name suggests, `race` returns **`first promise with shortest delay`** whether it is `resolved` or `rejected`.

For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second  (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (resolved)
Promise 4 ==> 4 seconds (resolved)
Promise 5 ==> 5 seconds (resolved)

So, it will return us Promise 1 because it was the **first one being returned.**

A more formal way to put it is this:

The `Promise.race` method in JavaScript is used to handle multiple promises concurrently, but it resolves or rejects as soon as the **first promise in the input array settles, either by resolving or rejecting**. 
This can be useful when you're interested in the result of the first promise to complete, regardless of whether it's a success or failure.

Lets look at this example where the first promise resolves:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.race(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```
You should see a response like this:
```
First promise resolved: Promise 2 resolved
```

Lets look at this example where the first promise rejects:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_,reject) =>
  setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.race(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```
You should see a response like this:
```
At least one promise rejected: Promise 2 rejected
```

Please note: `race` does not care if all are resolved or all are rejected. It will give you **first settled result** whether it is resolved or rejected.

## Promise.any() <a name="promiseany-section"></a>

It is somewhat similar to `race` method but with few minor differences:

- It will return with **first resolved promise**.

For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second  (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (resolved)
Promise 4 ==> 4 seconds (resolved)
Promise 5 ==> 5 seconds (resolved)

So, it will return us Promise 3 because it was the **first one being resolved.**

- If all promises are rejected, it will give you an aggregated error.

For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (rejected)
Promise 4 ==> 4 seconds (rejected)
Promise 5 ==> 5 seconds (rejected)

So, now it will return an aggregated result like this:
```
[AggregateError: All promises were rejected]
```

Lets look at first example:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.any(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });

```
You will find a similar response as `race` method:
```
First promise resolved: Promise 2 resolved
```

Lets look at another example:

```javascript
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_,reject) =>
  setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((resolve) =>
  setTimeout(() => resolve("Promise 3 resolved"), 800)
);

const promisesArray = [promise1, promise2, promise3];
```

If you run this snippet in which the promise with shortest delay `promise2` of `500ms` is rejected and `promise3` which has next shortest delay `800ms` then:

- `race` will return `promise2` with rejected reason 
- `any` will return `promise3` with resolved result.

Run it with `promise.any`:
```javascript

Promise.any(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```

You will get this response:
```
First promise resolved: Promise 3 resolved
```

Run it with `promise.race`:
```javascript
Promise.race(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```

You will get this response:
```
At least one promise rejected: Promise 2 rejected
```

Below is the case of all promises being rejected with `promise.any`:
```javascript
const promise1 = new Promise((_, reject) =>
  setTimeout(() => reject("Promise 1 rejected"), 1000)
);
const promise2 = new Promise((_, reject) =>
  setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((_, reject) =>
  setTimeout(() => reject("Promise 3 rejected"), 800)
);

const promisesArray = [promise1, promise2, promise3];

Promise.any(promisesArray)
  .then((results) => {
    console.log("First promise resolved:", results);
  })
  .catch((error) => {
    console.error("At least one promise rejected:", error);
  });
```

Then you will see a response like this:
```
At least one promise rejected: [AggregateError: All promises were rejected] {
  [errors]: [ 'Promise 1 rejected', 'Promise 2 rejected', 'Promise 3 rejected' ]
}
```

In contrast, the same code with `race` method will return this:
```
At least one promise rejected: Promise 2 rejected
```

## Difference between Promise.race() and Promise.any() <a name="difference2"></a>

We have already uncovered the differences of `race` and `any` in coding, lets further discuss them theoretically:

Both `Promise.race` and `Promise.any` are methods used to handle multiple promises concurrently, but they have different behaviors when it comes to resolving and rejecting. Here are the key differences between the two methods:

### Resolution Behavior:

**Promise.race**: Resolves as soon as the first promise in the input array settles, whether it's resolved or rejected. The returned promise adopts the outcome (either resolve or reject) of the first settled promise.
**Promise.any**: Resolves as soon as any one of the input promises resolves. It doesn't matter if the other promises reject. The returned promise adopts the resolved value of the first resolved promise.

### Rejection Handling:

**Promise.race**: If the promise that settles first is rejected, the returned promise will also reject with the same rejection reason.
**Promise.any**: If all input promises reject, the returned promise will reject with an aggregated error containing the reasons of all rejected promises. It only resolves if at least one promise resolves.

### Use Cases:

**Promise.race**: Useful when you want to implement scenarios like a timeout mechanism where you want to respond to the first promise to complete, regardless of whether it succeeds or fails.
**Promise.any**: Useful when you want to handle the case where at least one promise out of multiple promises succeeds, and you're interested in the result of the first resolving promise.

## Conclusion
So far, we have learned about [Callback Hell and its solution](https://dev.to/shameel/callback-callback-hell-promise-chaining-and-asyncawait-in-javascript-120i) as well. Then we explored [promises](https://dev.to/shameel/understanding-promise-in-javascript-45kc) in great detail and now we have learned about some of the important methods and their use-cases in real-life.

Follow me for more of such content:
LinkedIn: https://www.linkedin.com/in/shameeluddin/
Github: https://github.com/Shameel123