Implement Polyfill for promise.all

Cover Image for Implement Polyfill for promise.all

According to MDN

The Promise.all() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input's promises rejects, with this first rejection reason.

From the definition the promise.all function can be breakdown to the following points:

  • It accepts an array of promises (empty array is valid, non promises are also valid)

  • It should return a single promise

  • The promise will resolve with the array of all the fullfilled promises or reject with the error message of first failed promise.

  • The results are returned in the same order as the promises are in the given array.

  • It will reject immediately upon any of the input promises rejecting.

Using Promise.all()

const p1 = Promise.resolve(100);
const p2 = "I am batman";
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p3 resolved");
  }, 100);
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [100, "I am batman", "p3 resolved"]
});

Lets implement Polyfill for Promise.all()

  1. we create a new promise, the function should return this promise

  2. We iterate through the promises array and once any of the promise is resloved, we store the them in results array with the respective index

  3. we have to resolve the results array, once all the promises are resolved, every time a promise is resolved we increment promiseCompleted, so when the promiseCompleted is equal to the array length, then it means all the promises are resolved and we will resolve the results array

  4. The catch block catches the error of the promise and rejects with the error

export default function promiseAll(iterable) {
  return new Promise((resolve,reject)=>{
    const results = []
    let unresolved = iterable.length
    if(unresolved === 0){
      resolve(results)
    }
    iterable.forEach((item,index)=>{
      Promise.resolve(item).then((value)=>{
        results[index] = value
        unresolved-=1
        if(unresolved===0){
          resolve(results)
        }
      }
      ,(reason)=>{
        reject(reason)
      })
    })
  })
}

Test cases

// created a function task that takes two parameters and returns a promise
// first argument is the time duration
// second argument is a bolleon value
//     if true => resolves, if false => rejects
function task(time, shouldResolve = true) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (shouldResolve) {
        resolve(time);
      } else {
        reject('Rejected');
      }
    }, time);
  });
}

// 1
const taskList = [task(1000), task(5000), task(3000)];
myPromiseAll(taskList)
  .then(results => {
    console.log("results", results)
  })
  .catch(console.error);
// "results" [1000,5000,3000]

// 2
const taskList2 = [1, task(5000), task(3000)];
myPromiseAll(taskList2)
  .then(results => {
    console.log("results", results)
  })
  .catch(console.error);

// "results" [1,5000,3000]

// 3
const taskList2 = [1, task(5000,false), task(3000)];
myPromiseAll(taskList2)
  .then(results => {
    console.log("results", results)
  })
  .catch(console.error);

// "Rejected"