promise.race()
Prompt
Implement a function customPromiseRace that takes an array of promises and returns a new promise. It should behave like the native Promise.race() but you cannot use Promise.race in your implementation.
Playground
Promise.race is the simplest of all the Promise
combinators. Return a new Promise, loop through the
input, and the first promise to settle (resolve or reject)
should settle the outer promise too.
Use Promise.resolve(promise) to wrap each item (handles
non-promise values). Then chain
.then(resolve).catch(reject) on each one. The first one
to fire wins. You don't need any counters or result
arrays.
You might wonder: won't the later promises also call
resolve or reject? Yes, but a promise can only settle
once. Once the outer promise is resolved or rejected, all
further calls to resolve/reject are silently ignored.
Solution
Explanation
Promise.race is actually the simplest of all the Promise combinators. It returns a promise that settles as soon as the first promise in the array settles, whether that's a resolve or a reject.
Think of it like an actual race. You have multiple runners (promises). You don't care who comes second or third. You only care about the winner. The moment someone crosses the finish line, the race is over.
How the solution works
function customPromiseRace(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
Promise.resolve(promise).then(resolve).catch(reject);
});
});
}That's it. The entire implementation is just a loop that attaches .then(resolve).catch(reject) to every promise.
The reason this works is beautifully simple: a promise can only settle once. Once resolve or reject is called on our outer promise, calling them again does nothing. So even though every promise in the array will eventually settle and try to call resolve or reject, only the first one matters. All the later calls are silently ignored.
No counters, no results array, no index tracking. Just "whoever finishes first, pass their result to the outer promise."
Why is this different from Promise.all?
With Promise.all, you need every promise to succeed, and you need to collect all the results in order. That requires a counter, a results array, and careful index placement.
With Promise.race, you need exactly one result from whichever promise settles first. There's nothing to collect and nothing to count.
When would you use Promise.race?
The most common use case is implementing timeouts:
function fetchWithTimeout(url, ms) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject('Timeout!'), ms)
),
]);
}If fetch takes longer than ms milliseconds, the timeout promise rejects first and the race is over. This is a pattern you'll see in production code everywhere.