Deep dive into promise.all polyfill in javascript will help to understand the working of parallel promise calls using Promise.all and its implementation to handle parallel async API calls.
Anuj Sharma
Last Updated Jan 16, 2025
Promise.all is an important static method as part of Promise since it enables the parallel or simultaneous calling of multiple promises. This is a very common case in web development to call the multiple promises in parallel to achieve performance gain and in this case Promise.all is quite useful.
Going through the implementation of Promise.all polyfill will helps to understand the Promise.all behaviour in different use-case and its overall internal working. Let's dive into this.
Promise.all() is a static method of the Promise
constructor function (a.k.a. class), which can be invoked directly using the Promise. all()
method takes an iterable of promises as input and returns a single promise.
Promise.all(<Iterable of promises>)
Promise.all([]) // Iterable of promise can be blank
Here is how a static Promise.all(<Iterater of Promises>) function call works with an example.
In case, when all the promises which are part of the array(iterable) are fulfilled, and then a single promise is fulfilled containing an array of the fulfilment values of respective promises and returned by Promise.all(<Iterable of Promises>)
. It returns []
asynchronously when an empty array is passed.
// Case 1: When all promises get resolved
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise1: Resolved after 1sec!");
}, 1000);
});
const p2 = Promise.resolve("Promise2: Promise resolved immediately !!");
const p3 = 'Promise3: Converted to Promise';
Promise.all([p1, p2, p3])
.then((result) => {
console.log("result all ->", result);
})
.catch((error) => {
console.log("Error all ->", error);
});
// Output
'result all ->' [
'Promise1: Resolved after 1sec!',
'Promise2: Promise resolved immediately !!',
'Promise3: Converted to Promise'
]
It returns the first rejection reason if any input promises are rejected and no execution of the other promises if any.
// Case 2: One of the promises got rejected or throw an Error
const p1 = Promise.resolve("Promise1: Promise resolved immediately !!");
const p2 = 'Promise2: Converted to Promise';
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Promise3: Rejected after 1sec!");
// Or throw new Error("Promise3: Rejected after 1sec!")
}, 1000);
});
Promise.all([p1, p2, p3])
.then((result) => {
console.log("result all ->", result);
})
.catch((error) => {
console.log("Error all ->", error);
});
// Output
'Error all ->' 'Promise3: Rejected after 1sec!'
There are 3 major functionalities required as part of Promise.all
Promise.all([]) instanceof Promise // true
Step 1 - Define a new Promise instance that customAll
polyfill will going to return when resolve or reject invokes.
Step 2 - Define variables to capture 2 important thing, first the result
array to capture the results of input promises when they fulfilled and another one is the completed
counter to know when all the promises got successfully fulfilled.
Step 3 - Check for the empty iterator case and return the empty array asynchronously.
Step 4 - In this step, Loop over the promises array(iterable) and resolved each one of the promise.
Step 4.1 - If the promise got fulfilled then add the promise response to the result
array (which will be returned in case all the promises got fulfilled) and increment the completed
counter.
Step 4.2 - This step works like a breakpoint to resolve the new promise created at Step 2 with the result of all the promises captured part of result
array , when all the promises got successfully resolved means completed
counter equals to the length of the promise array.
Step 4.3 - In case if any of the input promise got rejected then the new promise got rejected with error message which was created at step 2. An error message return by the customAll
// Promise.all Polyfill
Promise.customAll = function (promisesItr) {
// Step 1: π all() return a Single Promise
return new Promise((resolve, reject) => {
// Step 2: π
// "result" to capture promise response.
// "completed" counter to count how many promises are completed.
const result = [];
let completed = 0;
// Step 3: π return empty [] if input iterable is empty.
if (promisesItr.length === 0) {
resolve(result);
}
// Step 4: π Execute each promise of promisesItr
for (let i = 0; i < promisesItr.length; i++) {
Promise.resolve(promisesItr[i])
.then((response) => {
// Step 4.1: π If promise fulfilled then store its response in result and increment the completed counter.
result[i] = response;
completed++;
// Step 4.2: π Check if all the promises got fulfilled,
// In this case, resolve and return the result array
if (completed === promisesItr.length) {
resolve(result);
}
})
.catch((error) => {
// Step 4.3: π If any promie fails, reject with error
reject(error);
});
}
});
};
Test case 1: All the promises got fulfilled
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise 1 Resolved after 1sec")
}, 1000);
});
const p2 = "Promise 2 Resolved !!"
const p3 = Promise.resolve("Promise3 resolved !!");
const p4 = "Promise4 resolved !!";
Promise.customAll([p1, p2, p3, p4])
.then((result) => {
console.log("Result customAll -> ", result);
})
.catch((error) => {
console.log("Error customAll ->", error);
});
/*
Output:
Result customAll -> ["Promise 1 Resolved after 1sec", "Promise 2 resolved", "Promise3 resolved !!", "Promise4 resolved !!"]
*/
Test case 2: One of the promise got rejected
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise 1 Resolved after 1sec")
}, 1000);
})
const p2 = Promise.reject("Promise2: Rejected Error !!");
// Or
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// reject("Promise2: Rejected Error !!");
// }, 2000);
// })
const p3 = Promise.resolve("Promise3 resolved !!");
const p4 = "Promise4 resolved !!";
Promise.customAll([p1, p2, p3, p4])
.then((result) => {
console.log("Result customAll -> ", result);
})
.catch((error) => {
console.log("Error customAll ->", error);
});
/*
Output:
Result customAll -> Promise2: Rejected Error !!
*/
Promise.all is a very frequently used promise static method to call the promises asynchronously, especially when calling multiple REST APIs in any application. Understanding Promise.all polyfill in-depth will make you understand the overall working on Promise.all and what all different outputs can be produced by Promise.all in case of different scenarios.
Hope this implementation of Promise.all will help in your day to day development work, also this will definitely help you in your next javascript interview since its a very frequently asked javascript interview questions as well. Happy Coding :)
Anuj Sharma
Last Updated Jan 4, 2025
Explore the most common ways to reverse a string in javascript including the most optimal way for frontend interviews with O(1) time complexity.
Anuj Sharma
Last Updated Jan 5, 2025
A comprehensive explanation about using javascript:void(0) in javascript. When to use javascript:void(0) and how it works with examples of using it with anchor tag.
Anuj Sharma
Last Updated Jan 2, 2025
Understand important web authorization techniques to enhance role-based authentication for any web application with popular techniques like Session & JSON Web Token (JWT)
Vivek Chavan
Last Updated Dec 23, 2024
You will get a clear understanding about working with any rest api and common concepts asked during interviews
Anuj Sharma
Last Updated Jan 9, 2025
Go through different ways to display dates using javascript date object. It covers examples of date object usage to understand the main concepts of javascript date object.
Anuj Sharma
Last Updated Dec 27, 2024
An Interview-focused explanation of Promise Polyfill in JavaScript which helps to understand both Functional and ES6 custom promise implementation.
Β© 2024 FrontendGeek. All rights reserved