promise.any()
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);
});
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.
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.
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.
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 theforEach
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 anAggregateError
constructed from therejectionReasons
array and the message 'All promises were rejected'.
- Increments the
- It calls
- If the input
promises
iterable is empty, the outer Promise is immediately rejected with anAggregateError
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.