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


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:

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.

Other Related Blogs

4 Ways to Reverse a String in JavaScript (JavaScript Interview)

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.

What is javascript:void(0) and How it Works?

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.

Explained Web Authorization Techniques - Session & JWT

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)

Ultimate guide to REST API calls using Fetch: Machine Coding Essential

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

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.

Promise Polyfill in JavaScript - Step by Step Explanation

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.

FrontendGeek
FrontendGeek

Β© 2024 FrontendGeek. All rights reserved