Polyfill: Create Promise.five()
Tags: javascript, career, webdev, programming
Published: 2022-08-23 14:50:00

Polyfill questions are common in Javascript interviews. Some of the most common ones:

1. [Array.map](https://jsvault.com/array-map)
2. [Array.reduce](https://jsvault.com/array-reduce)
3. [Promise.all](https://jsvault.com/promise-all)
4. [Promise.any](https://learnersbucket.com/examples/interview/promise-race-polyfill/)

etc.

Some time ago I was asked a to create a `Promise.five` polyfill, similar to `Promise.all` but with subtle differences.

This post will be a write up about how one can tackle a similar question when asked in an interview:

**Question: Create a function called minPromises which takes in a single number as an argument. Based on that argument it generates a function that can be used as Promise.five() or Promise.three(). Example: Promise.three() is similar to Promise.all(). It takes in a list of promises and returns when at least three promises resolve.**




### First Thoughts

It looked like we would have to wait for at least `min` promises to resolve. So a counter is definitely required.

We need to create a higher order function that takes in a number and returns another function. That function can be assigned to a new static property of `Promise` class like:

```
Promise.three = {}
Promise.four = {}
```

### Possible doubts that can arise:

1. What if `Promise.four()` is used with an array of promises of length 3.

2. Should the promise reject with reasons for all the promise failures or a common response for failure?

3. Should the return array length be same? Some promises will not used in the final result. What should be returned in their indices.

My interviewer cleared them out like this:

1. Reject straight away.
2. A common Rejection with a sample string will work.
3. Empty/null/undefined. Anything. But array order should be maintained just like `Promise.all`.

### Initial code:  

We start with the inner most function first. We have a `min` variable. We can loop through the promises. For every resolved promise we increase success counter. For every rejected promise we increase failure counter.

```
const min = 3;

function minPromise (promises) {

    return new Promise((resolve, reject) => {
        if (min > promises.length) return resolve("error");

        let counter = 0;
        let errCounter = 0;

        promises.forEach((promise) => {
            promise.then((res) => {
           //increase counter
}).catch((res) => {
          //increase errCounter
});
        });

    });

}
```

### Condition checks:

Now, we can put in the code to increase the counter. We should also start forming a result. For that we would need another `array`. We would also need the correct index of each promise, so we will have to make use of the second parameter of the `forEach` callback.

```
const min = 3;

function minPromise (promises) {

    return new Promise((resolve, reject) => {
        if (min > promises.length) return resolve("error");

        let counter = 0;
        let errCounter = 0;
        let resolvedValues = [];
        promises.forEach((promise, index) => {
            promise.then((res) => {
                counter++;
                resolvedValues[index] = res;
                if (counter === min) {
                    resolve(resolvedValues);
                }
            }).catch((res) => {
                errCounter++;
            });
        });

    });

}
```

### Reject case:

When does this promise reject? 
1. When the `min` is invalid, and 
2. when there are enough rejected promises that `counter` can never become `min`

```
const min = 3;

function minPromise(promises) {

    return new Promise((resolve, reject) => {
        if (min > promises.length) return reject("error");

        let counter = 0;
        let errCounter = 0;
        let resolvedValues = new Array(promises.length);
        promises.forEach((promise, index) => {
            promise.then((res) => {
                counter++;
                resolvedValues[index] = res;
                if (counter === min) {
                    resolve(resolvedValues);
                }
            }).catch((res) => {
                errCounter++;
                if (errCounter > promises.length - min) {
                    reject("error");
                }
            })
        });
    });

}
```

**Note:** Had to prepend reject with return otherwise Promise flow will continue. Any flow continues till the end until a return statement is reached or an error is thrown. An [SO answer](https://stackoverflow.com/questions/28896280/why-does-javascript-es6-promises-continue-execution-after-a-resolve), explaining the same.

### Wrapping the whole thing up (Pun intended):

The above code looks good. Now we have to wrap it in a function that takes in `min` as an input and can generate different versions of this. Using closures this should be easy.

```
const minPromises = (min) => {

    return function(promises) {

        return new Promise((resolve, reject) => {
            if (min > promises.length) return reject("error");

            let counter = 0;
            let errCounter = 0;
            let resolvedValues = new Array(promises.length);
            promises.forEach((promise, index) => {
                promise.then((res) => {
                    counter++;
                    resolvedValues[index] = res;
                    if (counter === min) {
                        resolve(resolvedValues);
                    }
                }).catch((res) => {
                    errCounter++;
                    if (errCounter > promises.length - min) {
                        reject("error");
                    }
                })
            });
        });

    }
}
```

Now the above can be used like :

```
Promise.four = minPromises(4);
Promise.six = minPromises(6);
```

And that's it. We are done.

## Afterthought

The question touched up on a lot of concepts like closure, currying, and of course promises. The main idea is to do some action when the individual promises resolve or reject.

Something like this is definitely easier if you have done the sample `Promise.all` polyfill. The solution could have used `async await` too instead of `.then`/`.catch`. This is what I could come up with during the interview.

[A codepen link](https://codepen.io/tushar8/pen/YzaGvjm?editors=0011)

Happy to receive any kind of feedback about this. Do let me know how you would have solve this?