Photo by MichaΕ Parzuchowski on Unsplash
Implementing a Promise.all Polyfill for Javascript Interviews
Introduction
In this blog post, we'll walk through the step-by-step implementation of a polyfill for the Promise.all
method in JavaScript. This polyfill allows developers to use Promise.all
in environments where it is not natively supported, ensuring consistent behavior across different platforms.
Check for Existing Implementation
Before implementing the polyfill, it's important to check if the environment already supports Promise.all
. If it doesn't, we can proceed with the polyfill implementation.
if (!Promise.all) {
// Proceed with polyfill implementation
}
Create the Polyfill Function
Implementing the Promise.all
polyfill involves several key steps to ensure correct behavior:
Input Validation: Check if the input is an array of promises. If not, reject the main promise with a
TypeError
.Empty Array Input: Check if the input array is empty than resolve with empty array
Initialization: Initialize an empty array to store the results of each promise and a counter to keep track of how many promises have settled.
Iteration Over Promises: Use a loop to iterate over each promise in the input array. For each promise:
Use
Promise.resolve
to ensure the promise is a proper promise object.Attach a
then
handler to handle fulfillment. Store the fulfillment value in the results array at the corresponding index.Attach a
catch
handler to handle rejection. If any promise rejects, reject the main promise with the reason of the first rejection.
Completion Check: Increment the counter in the
then
andcatch
handlers and check if all promises have settled. If all promises have settled (i.e., the counter equals the number of promises), resolve the main promise with the results array.
Here's the detailed implementation
if (!Promise.all) {
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
// Input validation
if (!Array.isArray(promises)) {
return reject(new TypeError('arguments must be an array'));
}
// return empty array if input is given as empty array
if(promises.length === 0) {
resolve([])
}
let results = [];
let completed = 0;
// Iterate over promises
promises.forEach((promise, index) => {
// Ensure promise is a proper promise object
Promise.resolve(promise)
// Handle fulfillment
.then((value) => {
results[index] = value;
completed++;
// Check if all promises have settled
if (completed === promises.length) {
resolve(results);
}
})
// Handle rejection
.catch((reason) => {
reject(reason);
});
});
});
};
}
Testing the Polyfill:
Testing is crucial to ensure that our polyfill works as expected. Let's add some test cases to cover different scenarios:
// Test case 1: All promises resolve
const promises1 = [
Promise.resolve('Success 1'),
Promise.resolve('Success 2'),
Promise.resolve('Success 3')
];
Promise.all(promises1)
.then(results => console.log(results))
.catch(error => console.error(error));
// Test case 2: Some promises reject
const promises2 = [
Promise.resolve('Success 1'),
Promise.reject('Error 2'),
Promise.resolve('Success 3')
];
Promise.all(promises2)
.then(results => console.log(results))
.catch(error => console.error(error));
// Test case 3: Empty array of promises
const promises3 = [];
Promise.all(promises3)
.then(results => console.log(results))
.catch(error => console.error(error));
These test cases cover scenarios where all promises resolve, some promises reject, and an empty array of promises is provided.
Additional Resources: