promise.any()

Hard Important

Prompt

Implement a function customPromiseAny that takes an iterable (e.g., an array) of promises as input and returns a new promise that resolves with the value of the first fulfilled promise in the input iterable, or rejects with an AggregateError if all promises are rejected.

The function should have the following signature:

/**
* Implement the `customPromiseAny` function
* @param {Array<Promise>} promises - An iterable of Promises
* @returns {Promise<Array>} - A new Promise that resolves with the value of the first
* fulfilled promise in the input iterable, or rejects with
* an AggregateError if all promises are rejected.
*/
function customPromiseAny(promises) {
// Your implementation here
}

The customPromiseAny function should behave similar to the native Promise.any method in JavaScript, but you cannot use Promise.any in your implementation.

Here are some examples to test your solution:

const promise1 = Promise.reject('Error 1');
const promise2 = Promise.resolve(2);
const promise3 = Promise.reject('Error 3');

customPromiseAny([promise1, promise2, promise3])
.then((value) => {
console.log(value); // Expected output: 2
})
.catch((error) => {
console.error(error);
});
Hint 1

Create a new Promise that will be returned by the customPromiseAny function. This Promise will be resolved with the value of the first fulfilled promise in the input iterable, or rejected with an AggregateError if all promises are rejected.

Hint 2

Initialize an array to store the rejection reasons from the input promises. This array will be used to construct the AggregateError in case all promises are rejected.

Hint 3

Iterate over the input iterable of promises. For each promise, chain a then handler to handle the resolved value, and a catch handler to handle the rejected promise. In the then handler, resolve the outer Promise with the resolved value. In the catch handler, store the rejection reason in the array of rejection reasons.

Hint 4

After handling all promises, check if all promises were rejected. If the array of rejection reasons has a length equal to the length of the input iterable, it means that all promises were rejected. In this case, reject the outer Promise with an AggregateError constructed from the array of rejection reasons and an appropriate error message.

Solution

Explanation

  • The function takes an array of promises as input.
  • It initializes an empty array rejectionReasons to store the rejection reasons from the input promises.
  • It initializes a variable rejectedPromisesCount to keep track of the number of rejected promises.
  • The function creates and returns a new Promise.
  • Inside the Promise executor function, it iterates over the input promises array using the forEach method.
  • For each promise:
    • It calls Promise.resolve(promise) to ensure that the value is a Promise object, even if it's a non-Promise value.
    • It chains a then handler that resolves the outer Promise with the resolved value of the first fulfilled promise.
    • It chains a catch handler to handle the rejected promise, which:
      • Increments the rejectedPromisesCount counter.
      • Stores the rejection reason in the rejectionReasons array.
      • If all promises have been rejected (rejectedPromisesCount === promises.length), it rejects the outer Promise with an AggregateError constructed from the rejectionReasons array and the message 'All promises were rejected'.
  • If the input promises iterable is empty, the outer Promise is immediately rejected with an AggregateError with an empty array and the message 'No promises were provided'.

Key Aspects

  • Handling non-Promise values: By calling Promise.resolve(promise), the solution ensures that even non-Promise values are wrapped in a Promise object before being handled.
  • Resolving with the first fulfilled promise: The then handler is chained to each Promise, which resolves the outer Promise with the value of the first fulfilled promise.
  • Collecting rejection reasons: The catch handler is chained to each Promise to handle rejected promises. It stores the rejection reason in the rejectionReasons array.
  • Rejecting with AggregateError: If all promises are rejected (rejectedPromisesCount === promises.length), the outer Promise is rejected with an AggregateError constructed from the rejectionReasons array and an appropriate error message.
  • Handling empty input iterable: If the input promises iterable is empty, the outer Promise is immediately rejected with an AggregateError with an empty array and an appropriate error message.
00:00

Table of Contents