Skip to Content
JS NativePromises

Custom Implementations of Promise.all, Promise.any, Promise.allSettled, and Promise.race

Learn how JavaScript’s static Promise methods work by building them from scratch. This page covers custom implementations of Promise.all, Promise.allSettled, Promise.any, and Promise.race — useful for understanding async behavior, debugging, and preparing for interviews.

Promise.all

The Promise.all() static method takes an iterable of promises and returns a single Promise that:

  • fulfills when all input promises have fulfilled, returning an array of results in the original order
  • rejects immediately if any promise rejects, with the first rejection reason

This example includes a custom implementation of Promise.all() that resolves all promises and preserves their order, even if they complete at different times.

Promise.all
function myPromiseAll(promises) { return new Promise((resolve, reject) => { if (!Array.isArray(promises)) { return reject(new TypeError("Argument must be an array")); } const results = []; let completedPromises = 0; for (let index = 0; index < promises.length; index++) { Promise.resolve(promises[index]) .then((value) => { results[index] = value; console.log(value); completedPromises += 1; if (completedPromises === promises.length) { resolve(results); } }) .catch(reject); } if (promises.length === 0) { resolve([]); } }); } const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 3000, "first"); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "second"); }); const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, "third"); }); myPromiseAll([promise1, promise2, promise3]).then((values) => { console.log(values); }); // second // first // third // [ 'first', 'second', 'third' ]

Promise.allSettled

The Promise.allSettled() method returns a promise that resolves after all promises in the input iterable have settled, regardless of whether they were fulfilled or rejected. Each result is an object with a status of either "fulfilled" or "rejected" and contains either the value or the reason.

This example demonstrates a custom implementation of Promise.allSettled() using .then() and .catch() handlers for consistent result formatting.

Promise.allSettled
const rejectHandler = (reason) => ({ status: "rejected", reason }); const resolveHandler = (value) => ({ status: "fulfilled", value }); Promise.customAllSettled = function (promises) { const convertedPromises = promises.map((p) => Promise.resolve(p).then(resolveHandler, rejectHandler), ); return Promise.all(convertedPromises); }; Promise.customAllSettled([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000), ), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]) .then(console.info) .catch(console.error); // [ // { status: 'fulfilled', value: 1 }, // { // status: 'rejected', // reason: Error: Whoops!... // }, // { status: 'fulfilled', value: 3 } // ]

Promise.any

The Promise.any() method returns a promise that fulfills as soon as any of the input promises is fulfilled. If all promises reject, it rejects with an AggregateError containing all rejection reasons.

This example demonstrates a custom implementation of Promise.any() that resolves with the first successful result or throws an aggregate error if none succeed.

Promise.any
Promise.customAny = function (promises) { return new Promise((resolve, reject) => { const errors = []; let remaining = promises.length; if (remaining === 0) { return reject(new AggregateError([], "All promises were rejected")); } promises.forEach((promise, index) => { Promise.resolve(promise) .then(resolve) .catch((error) => { errors[index] = error; remaining -= 1; if (remaining === 0) { reject(new AggregateError(errors, "All promises were rejected")); } }); }); }); }; const promise1 = Promise.reject(0); const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "quick")); const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "slow")); const promises = [promise1, promise2, promise3]; Promise.customAny(promises).then((value) => console.log(value)); // quick

Promise.race

The Promise.race() method returns a promise that settles as soon as the first input promise settles — whether it fulfills or rejects. This makes it useful when you’re interested only in the fastest outcome, regardless of its result.

This example includes a custom implementation of Promise.race() that resolves or rejects based on whichever promise finishes first.

Promise.race
Promise.customRace = function (promises) { return new Promise((resolve, reject) => { for (const promise of promises) { Promise.resolve(promise).then(resolve, reject); } }); }; Promise.customRace([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000), ), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]).then(console.log); // 1
Last updated on