Promise.all

Let’s say we want many promises to execute in parallel and wait until all of them are resolved. Then Promise.all is the right candidate which takes an array of promises and returns a new promise.

Let's understand how Promise.all works.

Promise Resolves when:

  1. Promises which will be fulfilled after sometime (Eg: API which fulfills after 10 seconds)
  2. Promises that have been already fulfilled (Eg: API which fulfils before passing to .all())
  3. Non-promises based functions, variables etc, (Eg: Function which returns a value)

Promise Rejects when:

  1. If one of promise get rejected, then Promise.all immediately rejects, completely ignoring about the other ones on the list.

We are going to see an example of Promise.all and then we will implement it.

Example:

/* A simple function to sleep for certain time and then resolve it */
var sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));

// Async function
var asyncFunz = async () => {
  await sleep(2000); // await method will wait for 2 seconds and return below string
  return 'Executed after 2 seconds';
};

/* Fetch user information */
var promise2 = fetch(`https://reqres.in/api/user/1`).then((res) => res.json());

/* A simple function which add's two numbers and return it */
var sum = (a, b) => a + b;

/* Adding above methods and some more to Promise.all method */
var myPromises = Promise.all([asyncFunz(), promise2, sum(1, 2), undefined, null, 1]);

/* Attaching .then, .catch methods to handle Promise.all */
myPromises.then((res) => console.log('resolved: ', res)).catch((err) => console.log('rejected: ', err));

// Above Promise.all resolves and log the result (Below line for result)
// resolved: ["Executed after 2 seconds", {data: {...}}, 3, undefined, null, 1]

In the above example, asyncFunz, promise2 are actual async functions and the rest of items in the array are a normal Function, Undefined, Null and 1.

From above example we can understand that Promise.all method accepts both async and non-async items, functions, variables etc,.

To write our custom promise.all(), we are going follow 3 steps.

Step 1:

/* Promise.all() custom function */
function promiseAll(promisesArr) {
  /* To keep the result of resolved promises */
  var result = Array(promisesArr.length);

  /* To keep track of how many promise got resolved */
  var counter = 0;

  /* To resolve/reject based on promisesArr items */
  return new Promise((resolve, reject) => {});
}

Step 2:

function promiseAll(promisesArr) {
  /* To keep the result of resolved promises */
  var result = Array(promisesArr.length);

  /* To keep track of how many promise got resolved */
  var counter = 0;

  /* To resolve/reject based on promisesArr items */
  return new Promise((resolve, reject) => {
    // Iterating the given promises array
    promisesArr.forEach((promise, index) => {
      // To handle both promise & non-promise in each iteration
      Promise.resolve(promise)
        .then((item) => {
          // Store the result
        })
        .catch((err) => {
          // If there is an error, reject it immediately
        });
    });
  });
}

Final Step:

function promiseAll(promisesArr) {
  /* To keep the result of resolved promises */
  var result = Array(promisesArr.length);

  /* To keep track of how many promise got resolved */
  var counter = 0;

  /* To resolve/reject based on promisesArr items */
  return new Promise((resolve, reject) => {
    // Iterating the given promises array
    promisesArr.forEach((promise, index) => {
      // We need to resolve each item in promises so that even if there is non-promise item we can handle it
      Promise.resolve(promise)
        .then((item) => {
          counter += 1; // Update the counter
          result[index] = item; // Store the result in the same order as given

          /* If counter is equal to promises.length then all promises are fulfilled */
          if (counter === promisesArr.length) {
            resolve(result); // All promises resolved so resolve outer promise
          }
        })
        .catch((err) => {
          reject(err); // If there is an error, reject the outer promise immediately
        });
    });
  });
}

Wrapping up

Above piece of code may not be same as how browser vendors would have implemented Promise.all() method, but you get the idea right how it works?.

I hope this post was useful and we all have learned something new. See you in my next post. My next post will be about how to write custom spread operator and how it works. If you are not subscribed, subscribe below :D

Join 305+ Readers

Sent out once every month. No spam 🤞