Let's talk about JavaScript Promises Methods

Let's talk about JavaScript Promises Methods

·

6 min read

Javascript is a single-threaded synchronous programming language. In many Javascript applications, we have to process asynchronous operations such as database calls, API requests etc. As these asynchronous events do not result in their values instantly, such types of asynchronous events are resolved using Promises in Javascript

Promises represent an asynchronous operation's eventual resolution or failure and its resultant value or error. Instead of final values being returned from such asynchronous calls, these calls return us a Promise which in turn gets settled after a certain period.

Today, we are going to look at 4 different ways we can resolve multiple promises at the same time using inbuilt javascript Promise methods, all(), allSettled(), race() and any()

Promise.all()

Promise.all() method takes in an array of promises to be settled and returns a single Promise. This returned Promise is resolved (fulfilled) when all the promises given as input are resolved without error and returns the resolved values in the form of an array similar to the input array of promise

However, this Promise is rejected when even one of the promises given is rejected. In this scenario, the Promise will return us the error from the first promise to reject as the result.

Let's take a look at the first case where all promises given are successfully resolved

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P1 success");
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P2 success");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 1500);
});

Promise.all([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((err) => console.error({ err }));
// Output : (3) ['P1 success', 'P2 success', 'P3 success']

As discussed, the output will be an array for the responses of the promises.

Now to look at the case where any of the promises were to fail,

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P1 success");
  }, 500);
});
// P2 fails
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P2 failure");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 2000);
});

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

// Output : {error: 'P2 failure'}

Now here, the Promise returns the error from the first rejected error

Promise.allSettled()

There is a slight issue with the Promise.all() method.

While handling multiple promises, if we want to get information about all the promises passed, whether fulfilled or rejected, the Promise.all() method is not sufficient as it rejects whenever even one promise fails when the rest of them are fulfilled

During this scenario, we would want to see the results of each Promise handled, fulfilled or rejected, Promise.allSettled() method will be the best choice.

Promise.allSettled() method takes in an array of promises to be resolved and in return, gives an array of objects for each promise consisting of the status of each promise, whether fulfilled or rejected and the subsequent value or reason for fulfilment or rejection of promise respectively.

Here is the code example for the same

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P1 success");
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P2 failure");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 2000);
});

Promise.allSettled([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((error) => console.log({ error }));

/*
Output:
(3) [Object, Object, Object]
0: {status: 'fulfilled', value: 'P1 success'}
1: {status: 'rejected', reason: 'P2 failure'}
2: {status: 'fulfilled', value: 'P3 success'}
length: 3
*/

Promise.race()

Unlike the above-mentioned methods, the Promise.race() method receives an iterable array of promises and returns a Promise that settles with the eventual state of the first Promise that settles.

This means Promise.race() returns the state of the first Promise whether it fulfils or rejects.

Following are the code examples where the .race() method returns us the resolved and the rejected response from the Promises

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P1 success"); // First to settle and fulfil
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P2 resolve");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 2000);
});

Promise.race([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((error) => console.log({ error }));

// Output : P1 success

Now when the first Promise to be resolved rejects,

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P1 failure"); // First to settle and rejects
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P2 resolve");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 2000);
});

Promise.race([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((error) => console.log({ error }));

// Output : {error: 'P1 failure'}

Promise.any()

In the implementation mentioned above of Promise.race(), in various cases, instead of the first settled Promise’s state, we might require the first “fulfilled” Promise’s state. For this, we will be required to use another method, Promise.any().

Promise.any() takes in an array of Promises to be settled and returns a Promise that is fulfilled when any of the Promises given as input is fulfilled with the value of the first fulfilled Promise.

However, when all of the Promises reject, Promise.any() rejects with an AggergateError containing an array of the reject reasons.

Let's see exactly how it works

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P1 failure"); // First to settle but rejects
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P2 resolve"); // Next to settle and resolves
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("P3 success");
  }, 2000);
});

Promise.any([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((error) => console.log({ error }));

// Output : P2 resolve
// Since, Promise.any() takes the first "fulfilled" Promise

Now when none of the Promises given succeed...

// All Promises reject

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P1 failure");
  }, 500);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P2 failure");
  }, 1000);
});

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("P3 failure");
  }, 2000);
});

Promise.any([p1, p2, p3])
  .then((res) => console.log(res))
  .catch((error) => console.log({ error }));

/*
Output : 
{error: Error}
error: AggregateError: All promises were rejected
        errors: (3) ['P1 failure', 'P2 failure', 'P3 failure']
        message: "All promises were rejected"
        stack: "AggregateError: All promises were rejected"

*/

That's all folks! I hope you found this blog useful. Now if you want to test the Promises I have made a website for the same to test all these methods, check it out:

Try Promise Worker to make this concept clearer. Lastly, thank you so much for giving me your time! I hope you have a great day!