create polyfill of promise.any() in javascript

this is the popular interview question in javascript where you need to create a polyfill of promise.any()

ยท

4 min read

so first understand the meaning of promise.any() what it does according to mdn docs

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

so what we should consider while creating pollyfill of promise any

  1. it will take array of promises and then return a single promise which means our polyfill returns single promise

  2. the promise which is returned form the polyfill resloves when any of the promise is resolved form array of promises

  3. it will reject with aggregator error (which is we will return string that all promises failed) if all the promises fail or empty array is given

so let's start the polyfill solution

let's cover the first point which is we will have to make our polyfill return a promise and also it takes input of array of promises

const Promiseany = (tasks) => { 
    return new Promise((resolve, reject) =>  {

    })
}

so this covers our first point we are creating a function which takes input array of promises and returns a new promise

for the second point we need to make sure when our any promise form the array of promises will resolve we will resolve our polyfill promise

const Promiseany = (tasks) => { 
    return new Promise((resolve, reject) =>  {
        tasks.forEach(task => {
            task.then((res) => { 
                resolve(res)
            }) 
        })
    })
}

so here we are now looping over our promises array which is tasks it will make sure when a promise is first resolved it will resolve the main promise

for the third point if all the promises fail or an empty array is passsed we need to reject with string which will mention all promise failed

const Promiseany = (tasks) => { 
    let failureCount = 0; // this will keep the count of the rejected promise
    return new Promise((resolve, reject) =>  {
        // if empty array is passed it will reject
        if(tasks.length === 0){
            reject("All Promise rejected")
        }
        tasks.forEach(task => {
            task.then((res) => { 
                resolve(res)
            }).catch((err) => {
                failureCount++ // increments the count of the rejected promise
                // if the rejected promises is equal to tasks length which is passed array of promise  
                if(failureCount === tasks.length){
                    reject("All Promise rejected")
                }
            }) 
        })
    })
}

so here we keep the count of the rejected promise in the variable failureCount it will be incremented in the catch block of each promise if it fails and finally when failure count is equals to tasks length which is basically the array of promise which is passed to our promiseany it will be rejected with error('All promise rejected')

there is also case handled for the empty array so when the tasks array length is zero we will reject with error('All promise rejected')


so here is the full implementation of our polyfill

const Promiseany = (tasks) => { 
    let failureCount = 0;
    return new Promise((resolve, reject) =>  {
        if(tasks.length === 0){
            reject("All Promise rejected")

        }
        tasks.forEach(task => {
            task.then((res) => { 
                resolve(res)
            }).catch((err) => {
                failureCount++
                if(failureCount === tasks.length){
                    reject("All Promise rejected")
                }
            }) 
        })
    })
}

const pErr = new Promise((resolve, reject) => {
  reject("Always fails");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "Done eventually");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "Done quick");
 });

Promiseany([pErr,pSlow,pFast]).then(res => console.log(res)).catch(err => console.error(err))
// Expected Output : Done quick

when all promises are rejected

const Promiseany = (tasks) => { 
    let failureCount = 0;
    return new Promise((resolve, reject) =>  {
        if(tasks.length === 0){
            reject("All Promise rejected")

        }
        tasks.forEach(task => {
            task.then((res) => { 
                resolve(res)
            }).catch((err) => {
                failureCount++
                if(failureCount === tasks.length){
                    reject("All Promise rejected")
                }
            }) 
        })
    })
}

const pErr = new Promise((resolve, reject) => {
  reject("Always fails");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(reject, 500, "Done eventually");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "Done quick");
 });

Promiseany([pErr,pSlow,pFast]).then(res => console.log(res)).catch(err => console.error(err))

// Expected output : All Promise rejected

when empty array is passed


const Promiseany = (tasks) => { 
    let failureCount = 0;
    return new Promise((resolve, reject) =>  {
        if(tasks.length === 0){
            reject("All Promise rejected")

        }
        tasks.forEach(task => {
            task.then((res) => { 
                resolve(res)
            }).catch((err) => {
                failureCount++
                if(failureCount === tasks.length){
                    reject("All Promise rejected")
                }
            }) 
        })
    })
}

Promiseany([]).then(res => console.log(res)).catch(err => console.error(err))

// Expected results : All Promise rejected

conclusion :- so this it folks thanks for reading till end hope my explanation was clear if any suggestion comment down below

ย