loading...
Cover image for How it works - Promise.all()

How it works - Promise.all()

gokulkrishh profile image Gokulakrishnan Kalaikovan Updated on ・4 min read

Originally posted here


promise.all

Hi People,

Today we will learn about how Promise.all method works!

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.

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)

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() function, we are going follow 3 steps.

Step 1:

  • Create a function called promiseAll which accepts a parameter called promisesArr.
  • This function will have two variables: result (Type: Array) & counter (Type: Number).
  • result variable is to store the result of items in promisesArr.
  • counter variable to keep the count of how many items resolved so far in promisesArr.
  • Finally, add Promise object to resolve/reject and return it (More info on step 2).
/* 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:

  • Iterate the given promisesArr inside new Promise() object so we can either catch or resolve the items at each iteration.
  • Each item from promisesArr is passed to Promise.resolve() method to handle both promise & non-promise items
  • Add .then() & .catch() chaining methods to Promise.resolve() method to handle when the items settles in each iteration.
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
        });
    });
  });
}

Step 3: (Final)

  • When the Promise.resolve() resolves, increment counter + 1.
  • Store the resolved item in result variable in the respective index. So that we can maintain the order of result.
  • If the counter length === promisesArr length, then resolve the promise.
  • If even one item in promiseArr is rejected, then discard result and reject the outer promise.
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
        });
    });
  });
}

Demo

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

Subscribe here


References:

Posted on by:

gokulkrishh profile

Gokulakrishnan Kalaikovan

@gokulkrishh

Web Dev @Thoughtworks, GDE for Web, Speaker, Curator at @thisweekinweb, Author of http://how-it-works.dev & github: http://github.com/gokulkrishh

Discussion

pic
Editor guide
 

Very nice post. Thanks!

 

Thanks. Subscribe to my newsletter for more.