JavaScript Promises Tutorial - Section 3: Static Methods
Promise.race() returns a Promise that settles as soon as any of the input Promises settles (either fulfills or rejects).
Promise.race([promise1, promise2, promise3])
.then(result => {
// Result from the FIRST settled Promise
})
.catch(error => {
// Error from the FIRST rejected Promise
});
const slow = new Promise(resolve =>
setTimeout(() => resolve('Slow'), 3000)
);
const fast = new Promise(resolve =>
setTimeout(() => resolve('Fast'), 1000)
);
Promise.race([slow, fast])
.then(result => {
console.log(result); // "Fast" (after 1 second)
});
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), ms);
});
}
function fetchWithTimeout(url, ms) {
return Promise.race([
fetch(url),
timeout(ms)
]);
}
fetchWithTimeout('/api/data', 5000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Request failed or timed out:', error));
const servers = [
'https://api1.example.com/data',
'https://api2.example.com/data',
'https://api3.example.com/data'
];
Promise.race(servers.map(url => fetch(url)))
.then(response => response.json())
.then(data => console.log('Got data from fastest server:', data))
.catch(error => console.error('All servers failed:', error));
function waitForUserAction() {
return new Promise(resolve => {
document.getElementById('saveBtn').onclick = () => {
resolve('manual');
};
});
}
function autoSave(delay) {
return new Promise(resolve => {
setTimeout(() => resolve('auto'), delay);
});
}
Promise.race([
waitForUserAction(),
autoSave(30000) // 30 seconds
])
.then(saveType => {
console.log(`Saving (${saveType})...`);
saveData();
});
| Feature | Promise.race() | Promise.all() |
|---|---|---|
| Resolves when | First Promise settles | All Promises fulfill |
| Rejects when | First Promise rejects | Any Promise rejects |
| Result | Single value | Array of values |
| Use case | Timeouts, fastest wins | Parallel operations |
async function fetchWithRetryAndTimeout(url, retries = 3, timeout = 5000) {
for (let i = 0; i < retries; i++) {
try {
const result = await Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
return await result.json();
} catch (error) {
console.log(`Attempt ${i + 1} failed:`, error.message);
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
fetchWithRetryAndTimeout('/api/data')
.then(data => console.log(data))
.catch(error => console.error('All attempts failed:', error));
function fetchWithCache(url) {
const cachePromise = caches.match(url);
const networkPromise = fetch(url).then(response => {
// Update cache in background
caches.open('v1').then(cache => cache.put(url, response.clone()));
return response;
});
return Promise.race([cachePromise, networkPromise])
.then(response => {
if (!response) return networkPromise;
return response;
});
}
function raceUntilSuccess(promises) {
return Promise.race(
promises.map(p =>
p.then(
value => Promise.resolve(value),
error => new Promise(() => {}) // Never resolves on error
)
)
);
}
raceUntilSuccess([
fetchFromServer1(),
fetchFromServer2(),
fetchFromServer3()
])
.then(data => console.log('First successful result:', data));
// Even though race settles after 1 second,
// the slow promise still completes after 3 seconds
Promise.race([
new Promise(resolve => {
setTimeout(() => {
console.log('Fast done');
resolve('Fast');
}, 1000);
}),
new Promise(resolve => {
setTimeout(() => {
console.log('Slow done'); // Still logs!
resolve('Slow');
}, 3000);
})
])
.then(result => console.log('Winner:', result));
// Output:
// Winner: Fast (after 1s)
// Slow done (after 3s)
// Promise.race([]) never settles!
Promise.race([])
.then(() => console.log('This never runs'))
.catch(() => console.log('This never runs either'));
Promise.race([
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Fast fail')), 100)
),
new Promise(resolve =>
setTimeout(() => resolve('Slow success'), 1000)
)
])
.then(result => console.log(result))
.catch(error => console.error(error.message)); // "Fast fail"
function loadImageWithTimeout(url, timeout = 5000) {
return Promise.race([
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('Failed to load image'));
img.src = url;
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Image load timeout')), timeout)
)
]);
}
loadImageWithTimeout('photo.jpg', 3000)
.then(img => document.body.appendChild(img))
.catch(error => console.error('Image load failed:', error.message));
Promise.race() settles with the first settled PromiseNext, we'll learn about Promise.allSettled() for handling mixed results!