Hone logo
Hone
Problems

Implement Promise.race

This challenge asks you to recreate the functionality of JavaScript's built-in Promise.race() method. Promise.race() is crucial for handling scenarios where you need to know the result of the first promise that settles (either resolves or rejects) from a given collection of promises. This is useful for implementing timeouts, competing asynchronous operations, and more.

Problem Description

You need to implement a function named myPromiseRace that accepts an iterable (e.g., an array) of promises and returns a new promise. This new promise should settle (resolve or reject) as soon as the first promise in the iterable settles.

Key Requirements:

  • The myPromiseRace function should accept a single argument: an iterable (like an array) of promises.
  • It should return a new Promise.
  • If any of the promises in the iterable resolve, the returned promise should resolve with the value of that first resolved promise.
  • If any of the promises in the iterable reject, the returned promise should reject with the reason of that first rejected promise.
  • The function should handle empty iterables correctly.
  • The function should handle non-promise values within the iterable.

Expected Behavior:

  • If the first promise to settle resolves with value V, myPromiseRace should resolve with V.
  • If the first promise to settle rejects with reason R, myPromiseRace should reject with R.
  • If the iterable is empty, the returned promise should remain pending forever (as per the standard Promise.race behavior).

Edge Cases:

  • An iterable containing no promises.
  • An iterable containing a mix of promises and non-promise values.
  • An iterable where multiple promises settle almost simultaneously.

Examples

Example 1:

const p1 = new Promise((resolve) => setTimeout(() => resolve('one'), 200));
const p2 = new Promise((resolve, reject) => setTimeout(() => reject('two'), 100));

myPromiseRace([p1, p2])
  .then(value => console.log(value))
  .catch(reason => console.error(reason));

Output:

two

Explanation: p2 rejects with 'two' after 100ms, which is faster than p1 resolving with 'one' after 200ms. Therefore, myPromiseRace rejects with 'two'.

Example 2:

const p3 = new Promise((resolve) => setTimeout(() => resolve('three'), 150));
const p4 = new Promise((resolve) => setTimeout(() => resolve('four'), 250));

myPromiseRace([p3, p4])
  .then(value => console.log(value))
  .catch(reason => console.error(reason));

Output:

three

Explanation: p3 resolves with 'three' after 150ms, which is faster than p4 resolving with 'four' after 250ms. Therefore, myPromiseRace resolves with 'three'.

Example 3: (Handling non-promise values and immediate settlement)

const p5 = new Promise((resolve) => setTimeout(() => resolve('fast'), 50));
const nonPromiseValue = 'instant';

myPromiseRace([p5, nonPromiseValue])
  .then(value => console.log(value))
  .catch(reason => console.error(reason));

Output:

instant

Explanation: Non-promise values are treated as already resolved promises. Since 'instant' is encountered before p5 settles, myPromiseRace resolves immediately with 'instant'.

Example 4: (Empty iterable)

myPromiseRace([])
  .then(value => console.log('Resolved:', value))
  .catch(reason => console.error('Rejected:', reason));
// This promise will never settle.

Output: (No output will appear in the console, as the promise remains pending indefinitely.)

Explanation: When an empty iterable is provided, Promise.race conventionally returns a promise that never settles.

Constraints

  • The input iterable can contain any number of promises or non-promise values, from zero to a very large number.
  • The function must be implemented using only native JavaScript features and Promise constructor. You cannot use the built-in Promise.race.
  • The implementation should be reasonably efficient and avoid unnecessary overhead.

Notes

  • Remember that Promise.race() settles as soon as any promise in the iterable settles, regardless of whether it resolves or rejects.
  • Consider how you will handle iterating through the input and attaching listeners to each promise.
  • Think about how to ensure that once the myPromiseRace promise settles, no further actions from other promises affect its state.
  • Non-promise values in the iterable should be treated as promises that resolve immediately with that value.
Loading editor...
javascript