JavaScript Promise.race() Method
Get the first result from multiple competing promises
Introduction
Promise.race() is the competitive sibling of the Promise family. It returns as soon as the first promise settles—whether that's a success or failure. Think of it as a race where the first to cross the finish line wins.
Syntax
Promise.race(iterable);
Parameters:
iterable: An iterable (usually an array) of Promise objects
Returns:
- A Promise that settles as soon as one of the input promises settles
- Adopts the status and value/reason of the first settled promise
Basic Usage
const promise1 = new Promise((resolve) => setTimeout(resolve, 500, 'one'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'two'));
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // 'two' - promise2 was faster
});
Real-World Examples
Timeout Implementation
The most common use case: adding timeouts to promises.
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms),
);
return Promise.race([promise, timeout]);
}
// Usage
try {
const data = await withTimeout(fetchData(), 5000);
console.log(data);
} catch (error) {
console.error(error.message); // 'Timeout' if > 5 seconds
}
Multiple API Endpoints
Fetch from multiple sources and use whoever responds first:
async function getCachedData(key) {
const sources = [fetchFromCache(key), fetchFromCDN(key), fetchFromAPI(key)];
try {
return await Promise.race(sources);
} catch (error) {
// All sources failed
throw new Error('All data sources failed');
}
}
Redundant Services
async function getWeather(location) {
const providers = [
fetchWeatherOpenWeather(location),
fetchWeatherWeatherAPI(location),
fetchWeatherAccuWeather(location),
];
// Use whoever responds fastest
return await Promise.race(providers);
}
Promise.race() vs Other Methods
Promise.race() - First to Finish
// Returns first result (success or failure)
const result = await Promise.race([fast, slow]);
Promise.all() - All Must Succeed
// Waits for all, fails on first error
const results = await Promise.all([p1, p2, p3]);
Promise.allSettled() - Wait for All
// Waits for all, returns all results
const results = await Promise.allSettled([p1, p2, p3]);
Promise.any() - First Success (ES2021)
// Returns first success, ignores rejections
const result = await Promise.any([p1, p2, p3]);
Important Considerations
Failures Count
Promise.race() doesn't care about success vs failure—it's purely about who finishes first.
const slowSuccess = new Promise((resolve) =>
setTimeout(() => resolve('success'), 1000),
);
const fastFailure = new Promise((_, reject) =>
setTimeout(() => reject(new Error('fail')), 100),
);
try {
await Promise.race([slowSuccess, fastFailure]);
} catch (error) {
console.error(error.message); // 'fail' - failure won
}
Empty Array
Promise.race([]); // Creates a promise that never settles
All Promises Start Immediately
All promises in the race begin executing at once. The race doesn't control when they start—it only controls which result you get back.
Common Pitfalls
Assuming Success
// ❌ Dangerous - might get a rejection
const result = await Promise.race([task1(), task2()]);
// ✅ Safe - handle both outcomes
try {
const result = await Promise.race([task1(), task2()]);
// Handle success
} catch (error) {
// Handle failure
}
Race Conditions
The name "race" is literal—be careful about race conditions in your application logic.
// Which one wins is non-deterministic
const result = await Promise.race([fetchFromServerA(), fetchFromServerB()]);
// Different runs might get different results
Lost Results
Only the first result matters. The other promises continue running, but their results are ignored.
// The slower promise still completes, but we ignore it
const winner = await Promise.race([fast(), slow()]);
// slow() still resolves, but we don't use its value
When to Use Promise.race()
✅ Good use cases:
- Implementing timeouts
- Redundant/fallback services
- Getting the fastest response from multiple sources
- Canceling operations with a timeout
❌ Avoid when:
- You need all results
- You need to ensure success
- The promises have side effects you need to complete
- You care about which specific promise wins
Advanced Pattern: Weighted Race
Race with preference for certain sources:
async function weightedRace(promises, preferredIndex = 0) {
try {
// Try preferred source first with short timeout
return await withTimeout(promises[preferredIndex], 200);
} catch {
// Fall back to race of all
return await Promise.race(promises);
}
}
Conclusion
Promise.race() is a powerful tool for time-sensitive operations and redundancy. Use it when speed matters more than which specific source provides the result. Just remember: in this race, anyone can win—even failure.
#javascript #async #promises #performance