Hone logo
Hone
Problems

Implement Promise.any in JavaScript

The Promise.any() static method takes an iterable of Promises as input and returns a single Promise that resolves as soon as any of the input Promises resolve. If all input Promises reject, the returned Promise rejects with an AggregateError. This functionality is crucial for scenarios where you need to get the result from the fastest-resolving asynchronous operation.

Problem Description

Your task is to implement a custom Promise.any() function in JavaScript that mimics the behavior of the native Promise.any().

What needs to be achieved: Create a function, let's call it myPromiseAny, that accepts an iterable (like an array) of Promises. This function should return a new Promise.

Key requirements:

  1. First to Resolve Wins: If any of the Promises in the input iterable resolve, myPromiseAny should immediately resolve with the value of the first Promise that resolves.
  2. Aggregate Rejection: If all Promises in the input iterable reject, myPromiseAny should reject with an AggregateError. This error object should contain an errors property, which is an array of all the rejection reasons from the input Promises.
  3. Empty Iterable: If the input iterable is empty, myPromiseAny should reject immediately with an AggregateError containing an empty errors array.
  4. Non-Promise Iterables: The function should handle cases where the iterable contains non-Promise values. These values should be treated as already-resolved Promises.

Expected behavior:

  • myPromiseAny([p1, p2, p3]) should resolve with the value of the first p that resolves.
  • myPromiseAny([p1, p2, p3]) should reject with an AggregateError if all p reject.
  • myPromiseAny([]) should reject with an AggregateError with an empty errors array.

Important edge cases to consider:

  • Handling an empty input array.
  • The order of resolution and rejection.
  • Iterables that contain a mix of Promises and non-Promise values.
  • The structure of the AggregateError object.

Examples

Example 1:

Input: [Promise.resolve(3), new Promise((resolve, reject) => setTimeout(reject, 100, 'foo')), new Promise((resolve, reject) => setTimeout(resolve, 200, 'bar'))]
Output: Promise resolves with the value 3
Explanation: The first Promise in the array resolves immediately with the value 3. Therefore, myPromiseAny resolves with 3 without waiting for the other Promises.

Example 2:

Input: [Promise.reject('error1'), Promise.reject('error2'), Promise.reject('error3')]
Output: Promise rejects with an AggregateError
Explanation: All Promises in the input array reject. myPromiseAny collects all the rejection reasons ('error1', 'error2', 'error3') into an AggregateError and rejects with it. The AggregateError will have an `errors` property containing ['error1', 'error2', 'error3'].

Example 3:

Input: [1, Promise.reject('error1'), Promise.resolve(2)]
Output: Promise resolves with the value 1
Explanation: The first element is not a Promise, so it's treated as an already resolved Promise with value 1. myPromiseAny resolves immediately with 1.

Example 4:

Input: []
Output: Promise rejects with an AggregateError
Explanation: An empty iterable is provided. myPromiseAny rejects immediately with an AggregateError whose `errors` property is an empty array.

Constraints

  • The input will be an iterable (e.g., an array) of Promises or values.
  • The implementation should be in plain JavaScript without using the native Promise.any() method.
  • You may use Promise.resolve(), Promise.reject(), and the Promise constructor.
  • The AggregateError object should be correctly instantiated and populated. If AggregateError is not natively available in the execution environment, you can create a custom error class that mimics its structure (e.g., a plain Error object with an errors property).

Notes

Consider using Promise.resolve() to wrap any non-Promise values in the input iterable to unify your handling logic.

Keep track of how many Promises have rejected. You'll need this count to determine when all Promises have rejected.

Think about how to manage the asynchronous nature of Promises and ensure that myPromiseAny resolves or rejects only once.

Loading editor...
javascript