Hone logo
Hone
Problems

Implementing Promise.any in JavaScript

Promise.any is a relatively new addition to JavaScript that allows you to wait for at least one promise in a list to resolve. It's incredibly useful for scenarios like retrying network requests or handling multiple data sources – you want to succeed if any of them succeed. This challenge asks you to implement the functionality of Promise.any from scratch.

Problem Description

Your task is to implement a Promise.any function that accepts an iterable (e.g., an array) of promises and returns a new promise. This new promise should resolve with the value of the first promise that resolves. If all promises reject, the new promise should reject with an AggregateError containing all the rejection reasons.

Key Requirements:

  • Resolution: The returned promise should resolve with the value of the first promise that resolves.
  • Rejection: If all promises reject, the returned promise should reject with an AggregateError. The AggregateError should have a errors property containing an array of all the rejection reasons.
  • Iterable Input: The function should accept an iterable (like an array) of promises as input.
  • Error Handling: Properly handle promise rejections and ensure the AggregateError is constructed correctly.
  • No External Libraries: You should implement this using only standard JavaScript features.

Expected Behavior:

The function should behave identically to the native Promise.any when available. It should handle both resolved and rejected promises correctly, and appropriately aggregate errors when all promises reject.

Edge Cases to Consider:

  • Empty Input: What should happen if the input iterable is empty? (Should reject immediately with an AggregateError)
  • Promises Rejecting Immediately: Handle cases where promises reject very quickly.
  • Promises Resolving/Rejecting in Any Order: The order of resolution/rejection is not guaranteed, so your implementation must be robust to this.
  • Non-Promise Input: While not strictly required, consider how your function should behave if the input iterable contains non-promise values. (You can choose to throw an error or ignore them).

Examples

Example 1:

Input: [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]
Output: 1
Explanation: The first promise resolves with 1, so Promise.any resolves with 1 immediately.

Example 2:

Input: [Promise.reject('Error 1'), Promise.reject('Error 2'), Promise.reject('Error 3')]
Output: AggregateError { errors: [ 'Error 1', 'Error 2', 'Error 3' ] }
Explanation: All promises reject.  Promise.any rejects with an AggregateError containing all the rejection reasons.

Example 3:

Input: [Promise.resolve(1), Promise.reject('Error 2'), Promise.resolve(3)]
Output: 1
Explanation: The first promise resolves with 1. The second promise's rejection is ignored after the first resolution.

Example 4:

Input: []
Output: AggregateError { errors: [] }
Explanation: The input is an empty array. Promise.any rejects with an AggregateError containing an empty array of errors.

Constraints

  • Input: The input must be an iterable.
  • Error Type: Rejection must be with an AggregateError object.
  • Performance: The solution should be reasonably efficient. Avoid unnecessary iterations or computations. While not a strict requirement, aim for a time complexity of O(n) in the worst case (where n is the number of promises).
  • AggregateError Constructor: Use the AggregateError constructor correctly. It takes a message and an array of errors.

Notes

  • Consider using Promise.allSettled as a starting point for understanding how to handle multiple promises concurrently. However, Promise.allSettled doesn't provide the specific behavior of Promise.any (resolving on the first success).
  • Think about how to efficiently track which promises have resolved or rejected.
  • The AggregateError constructor is relatively new. Ensure your target JavaScript environment supports it. If not, you might need to polyfill it.
  • Error handling is crucial. Make sure your code gracefully handles all possible scenarios.
Loading editor...
javascript