🟨 JavaScript
Hard
🕐 15 min

Promise.allSettled() Implementation

Goal: Understand the difference between Promise.all() and Promise.allSettled() and practice handling all promise outcomes.

💡 Hint
  1. Like Promise.all, your promiseAllSettled function should return a new Promise.
  2. The key difference: Promise.allSettled never rejects. It waits for all promises to complete.
  3. You will also need a results array and a settledCount counter.
  4. Iterate over the promises array. For each item:
    • Use Promise.resolve() for universal handling.
    • In .then(), add an object like { status: 'fulfilled', value: ... } to results.
    • In .catch(), add an object like { status: 'rejected', reason: ... } to results.
    • In both then and catch (or in finally), increment the settledCount.
    • When settledCount equals the length of the promises array, call resolve() with the results array.
  5. Don’t forget the case of an empty array.
👀 Solution
const promiseAllSettled = (promises) => {
  // Return a new promise. It will be resolved when all promises in `promises` are settled.
  // Importantly, this promise will never be rejected, unlike Promise.all.
  return new Promise((resolve) => {
    // An array to store the final states of all promises.
    const results = [];
    // A counter to track the number of settled promises.
    let settledCount = 0;
    // The total number of promises for convenience.
    const promisesCount = promises.length;
 
    // If the input array is empty, immediately resolve the promise with an empty array.
    if (promisesCount === 0) {
      resolve([]);
      return;
    }
 
    // Iterate over each item in the input array.
    promises.forEach((promise, index) => {
      // Wrap each item in `Promise.resolve()` to uniformly
      // handle both promises and regular values.
      Promise.resolve(promise)
        .then(value => {
          // If the promise is fulfilled,
          // save its result as an object with status 'fulfilled'.
          results[index] = { status: 'fulfilled', value };
        })
        .catch(reason => {
          // If the promise is rejected,
          // save the rejection reason as an object with status 'rejected'.
          results[index] = { status: 'rejected', reason };
        })
        .finally(() => {
          // The `finally` block executes in any case: after `then` and after `catch`.
          // This ensures that the counter is incremented for each promise, regardless of its outcome.
          settledCount++;
          // If the number of settled promises equals the total number,
          // it means all promises have completed.
          if (settledCount === promisesCount) {
            // Resolve the main promise, returning the array of results.
            resolve(results);
          }
        });
    });
  });
};

Solution Analysis:

  • Time Complexity: O(N), where N is the number of promises, plus the execution time of the longest promise.
  • Space Complexity: O(N) to store the results.

Task Description

You need to implement your own version of the built-in Promise.allSettled() static method.

The Promise.allSettled(iterable) method returns a promise that fulfills after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

For each outcome object, there is:

  • A status string. Either 'fulfilled' or 'rejected'.
  • If the status is 'fulfilled', a value is present.
  • If the status is 'rejected', a reason is present.

Examples

const p1 = Promise.resolve(3);
const p2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
 
promiseAllSettled([p1, p2]).then(results => {
  /*
  results will be:
  [
    { status: 'fulfilled', value: 3 },
    { status: 'rejected',  reason: 'foo' }
  ]
  */
  console.log(results);
});

Requirements

  • The function must be named promiseAllSettled.
  • It must accept an iterable object (e.g., an array).
  • It must return a single Promise.
  • The returned promise must fulfill with an array of result objects when all promises in the iterable have settled.
  • The order of the results must match the order of the promises.
  • The returned promise should never reject.

🧑‍💻 It's not a bug! It's a feature!

The code editor is intentionally hidden on mobile.

Believe me, it's for the best: I am protecting you from the temptation to code in less-than-ideal conditions. A small screen and a virtual keyboard are not the best tools for a programmer.

📖 Now: Study the task, think through the solution. Act like a strategist.

💻 Later: Sit down at your computer, open the site, and implement all your ideas comfortably. Act like a code-jedi!