Blog/NotesConcept

Promise.all Polyfill in JavaScript - Detailed Explanation [For Interviews]

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.

Expert

Anuj Sharma

Last Updated Jan 16, 2025


Advertisement

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.

Table of Content

  1. Understand Promise.all Static Method
  2. Expected Functionality Required in Promise.all Polyfill
  3. Promise.all Polyfill in JavaScript - Step by Step Explanation

Understand Promise.all Static Method

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.

Examples

Case 1: When all promises are successfully resolved

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'
]

Case 2: When any one of the promises got rejected or threw an "Error"

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!'

Expected Functionality Required in Promise.all polyfill

There are 3 major functionalities required as part of Promise.all

  1. In case when all input promises successfully fulfilled - Return a single fulfilled Promise with the array of result values of all respective promises.
  2. In case when any of the input promise got rejected - Returns the rejected error message only.
  3. In case of blank input promise - Returns a blank array asynchronously
    Promise.all([]) instanceof Promise // true

Promise.all Polyfill in JavaScript - Step by Step Explanation

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 Implementation Code:

// 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 !!
*/

πŸ“ŒFinal Note:

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 :)

⏩Learn Next

  1. Notes to Master Promise Methods in JavaScript: all(), allSettled(), race() and any()
  2. Promise Polyfill in JavaScript - Step by Step Explanation 

Share this post now:

Advertisement

πŸ’¬ Comments (0)

Login to comment

Advertisement

Flaunt You Expertise/Knowledge & Help your Peers

Sharing your knowledge will strengthen your expertise on topic. Consider writing a quick Blog/Notes to help frontend folks to ace Frontend Interviews.

Advertisement


Other Related Blogs

Understand JavaScript Date Object with Examples (for JavaScript 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.

HTTP/2 vs HTTP/1.1: What's the Key Difference?

Anuj Sharma

Last Updated Jan 29, 2025

Understand the difference between HTTP/2 vs HTTP/1.1 based on the various parameters, which helps to understand the improvement areas of HTTP/2 over HTTP 1.1

What is CORS ? Cross-Origin Resource Sharing Explained [For Interviews]

Anuj Sharma

Last Updated Dec 10, 2024

A brief explanation of Cross-Origin Resource Sharing (CORS) concept to enable client application accessing resources from cross domain and HTTP headers involved to enable resource access.

How to Format Phone Number in JavaScript (JavaScript Interview)

Anuj Sharma

Last Updated Jan 9, 2025

Learn the best & quickest way to format phone number in JavaScript with or without country codes. This will help websites to show the phone numbers in a more human-readable format.

5 Different Ways to Reload Page in JavaScript (Frontend Interview)

Anuj Sharma

Last Updated Jan 17, 2025

Explore the 5 most efficient ways to Refresh or Reload page in JavaScript similar to location.reload(true), and identify the appropriate use cases to use one of these different approaches.

5 Ultimate Rules to master this keyword in JavaScript

Anuj Sharma

Last Updated Feb 22, 2025

Easy to understand 5 rules, that cover the behaviour of the "this" keyword in different contexts and helps you to master this keyword for any javascript interview.

FrontendGeek
FrontendGeek

Β© 2024 FrontendGeek. All rights reserved