Methods of Promise: .all(), .any() , .finally(), .race()
Tags: javascript, codenewbie, tutorial, beginners
Published: 2021-08-07 10:28:41

In the previous posts of this series, I've shown the `resolve` and `reject` methods of a *Promise* and also how to retrieve data from a *Promise* using `Promise.then()` and `Promise.catch()` methods. 
[ https://dev.to/swarnaliroy94/retrieving-data-from-promise-then-catch-3onk ]

We can make this process more compact using `Async/Await`, which is most popularly used in projects. But, before writing about *Async/Await*, I want to make the readers familiar with some other methods of Promise.

The methods that I'm going to show in this post are `Promise.all()`, `Promise.race()`, `Promise.any()` & `Promise.finally()`.

Let's get started then!!

###:black_medium_square: Promise.all() Method

:point_right: The `Promise.all()` method accepts an *iterable Object*, such as an *Array of promises* as an *input* and returns a *single promise* that resolves to a *result array* of the input promises.
:point_right: When all input promises have been *resolved* or the iterable input *does not contain* a promise, the returned promise will be *resolved*. 
:point_right: It *rejects* immediately when an input promise rejects or non-promise *throws an error* and will reject with that *first rejection message* / *error message*.
:point_right: It is often used when there are many *asynchronous tasks* involved that the overall code relies on to work successfully - all of the ones we want to do before we continue to *execute* the code.
:point_right: This method aggregates the results of *multiple* promises.

#### Fulfillment of Promise.all()

:small_blue_diamond: When an *empty iterable* is passed, the promise returned by this method is executed *synchronously*. The resolved value will be an *empty array*.
:small_blue_diamond: When a *non-empty iterable* is passed, and all of the promises *fulfill* or are *not promises*,the promise returned by this method will be executed *asynchronously*.

Following is an *example* of `Promise.all()` Method :point_down:

```js
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 300, "resolved");
}); //will be resolved after 300ms

const promise2 = 93; //non-promise

const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "resolved2");
}); // will be resolved after 100ms

Promise.all([promise1, promise2, promise3])
  .then((values) => {
    console.log(values);
  })
  .catch((err) => {
    console.log(err);
  });

//expected output: [ 'resolved', 93, 'resolved2' ]
```

#### Rejection of Promise.all() : Fail-Fast Behavior

`Promise.all()` shows *fail-fast* behavior, that is, Promise.all() *asynchronously* rejects with the value of the promise that *rejected*, if any of the passed-in elements are *rejected*. 

For example, if we pass in *two promises* that resolve after a timeout and *one promise* that rejects immediately, then *Promise.all()* will reject immediately. It *does not depend* on if the other promises have *resolved*. The following *example* just does the same!

```js
const pro1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("one"), 1000);
});

const pro2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("two"), 2000);
});

const pro3 = new Promise((resolve, reject) => {
  setTimeout(() => reject("rejected"), 3000);
});

Promise.all([pro1, pro2, pro3])
  .then((values) => {
    console.log(values);
  })
  .catch((error) => {
    console.log(error);
  });

  //expected output: rejected
```
Let's move to another method which is `Promise.any()`.

###:black_medium_square: Promise.any() Method

:point_right: The `Promise.any()` takes an *iterable Object*, such as an *Array of promises* as an *input*. Once a promise is *fulfilled*, a *single promise* is returned and the promise is *resolved* using the value of the promise.
:point_right: If no promises in the iterable fulfill (if all of the given promises are *rejected*), then the returned promise is rejected with an *AggregateError* (that groups together individual errors).

#### Fulfillment of Promise.any()

:small_blue_diamond: Unlike `Promise.all()`, this method is used to return the *first promise* that *fulfills*.
:small_blue_diamond: It is *short-circuited* right after a promise is *completed*, so as soon as a promise is *fulfilled*, it will not wait for other promises to *complete*.
:small_blue_diamond: When a *non-empty* iterable is passed, and any of the promises fulfill, or are *non-promises*, then the promise returned by this method is fulfilled *asynchronously*.

For Example, the following code snippet will resolve the *QuickyDone* promise first as it is resolved after *100ms* and the other one resolves after *500ms*. It will not wait for any other promise to be fulfilled but immediately return the *first promise* that resolves.

```js
const SlowlyDone = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "Done slowly");
}); //resolves after 500ms

const QuicklyDone = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "Done quickly");
}); //resolves after 100ms

const Rejection = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "Rejected"); //always rejected
});

Promise.any([SlowlyDone, QuicklyDone, Rejection])
  .then((value) => {
    console.log(value);
    //  QuicklyDone fulfils first
  })
  .catch((err) => {
    console.log(err);
  });

//expected output: Done quickly
```
#### Rejection of Promise.any()

:small_blue_diamond: Promise.any() rejects with an AggregateError if no promise fulfils.
:small_blue_diamond: The *AggregateError* object represents an error when *several* errors need to be wrapped in a *single error*. It is thrown when multiple errors need to be reported by an operation.

An *example* is shown below :point_down: 

```js
const Rejection = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "Rejected"); //always rejected
});

Promise.any([Rejection])
  .catch((err) => {
    console.log(err);
  });

// expected output: "AggregateError: No Promise in Promise.any was resolved"
```
######:star: Note that, Promise.any() was supported in *node.js 15.0.0*. If your node.js version is *older* than that, the console might show a *TypeError: Promise.any is not a function* message, so you need to update it and try again.

###:black_medium_square: Promise.prototype.finally() 

:point_right: The `finally()` method returns a *Promise*.
:point_right: When a Promise is *completed*, either *resolved* or *rejected*,this specified callback function is executed.
:point_right: This helps to avoid duplicating code in both the promise's then() and catch() handlers.
:point_right: The finally() method will help if you're going to do any processing or cleanup work once a promise is made, regardless of the outcome.

The following is a simple *example* of this method.:point_down: 

```js
const addition = (a, b) =>
  new Promise((resolve, reject) => {
    if (typeof a == "number" && typeof b == "number") {
      resolve(a + b);
    } else {
      reject("Not a Number");
    }
  });

addition(10, 5)
  .then((response) => {
    console.log(response);
  })
  .catch((err) => {
    console.log(err);
  })
  .finally(() => {
    console.log("Numbers are added");
  });

  /* expected output: 15
                     Numbers are added */
```

###:black_medium_square: Promise.race() Method

:point_right: The `Promise.race()` method returns a *Promise* that is resolved or rejected, as soon as one of the promises in an *iterable*, such as an *array*, fulfills or rejects, with the value or reason from that Promise. 
:point_right: The promise returned will be forever *pending*, if the iterable passed is *empty*.
:point_right: `Promise.race()` will resolve to the first value found in the iterable, if the iterable contains one or more *non-promise* value or an *already settled* promise.

Let's see an *example* of *Promise.race()* with setTimeout :point_down:

```js
const pro1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("one"), 200);
});

const pro2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("two"), 100);
});

Promise.race([pro1, pro2])
  .then((response) => {
    console.log(response); //output: two
  })
  .catch((err) => {
    console.log(err);
  });

const pro3 = new Promise((resolve, reject) => {
  setTimeout(() => reject("rejected"), 300);
});

const pro4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("four"), 400);
});

Promise.race([pro3, pro4])
  .then((response) => {
    console.log(response);
  })
  .catch((err) => {
    console.log(err);
  }); //output: rejected

```
In the first case, *pro2(100ms)* is faster than *pro1(200ms)*, so the *output* shows *two*. In the second case, *pro3(300ms)* is faster than *pro4(400ms)*, so the promise rejects. So basically, **Promise.race() takes the first settled Promise**

If we take this same example and pass all the promises inside `Promise.race()`, it will return *two* as *output*, as the *pro2* is the *fastest* promise to be settled in this case.

```js
const pro1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("one"), 200);
});

const pro2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("two"), 100);
});

const pro3 = new Promise((resolve, reject) => {
  setTimeout(() => reject("rejected"), 300);
});

const pro4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("four"), 400);
});

Promise.race([pro1, pro2, pro3, pro4])
  .then((response) => {
    console.log(response);
  })
  .catch((err) => {
    console.log(err);
  });

//output: two
```
##### In this post, we have learnt about four important methods of Promise which are popular while doing any project. Another important concept is *Chaining Promises*. Will write about it in the next post.