Promise.any() is a static Promise method that takes an array of promises and returns a new promise that resolves with the value of the first successfully completed promise from the array. If all promises are rejected, it returns a rejected promise with AggregateError containing all errors. Useful for implementing fallback data sources, parallel requests, and performance improvements.
Main use cases:
“First successful result!” ✅
const promise1 = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Error 1')), 500)
);
const promise2 = new Promise(resolve =>
setTimeout(() => resolve('Success 2'), 200)
);
const promise3 = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Error 3')), 300)
);
Promise.any([promise1, promise2, promise3])
.then(result => console.log('Winner:', result)) // "Winner: Success 2"
.catch(error => console.error('All failed:', error));Promise.any() is a powerful tool in JavaScript asynchronous programming that allows executing multiple promises in parallel and working with the first successfully completed result. Unlike Promise.race(), which responds to the first completed promise (successful or not), Promise.any() waits for the first successful result.
Promise.any() takes an iterable object (usually an array) of promises and returns a new promise:
const promise1 = new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 1000));
const promise2 = new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000));
const promise3 = new Promise(resolve => setTimeout(() => resolve('Success 3'), 500));
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result)); // "Success 3" (first successful)One of the most common uses of Promise.any() is getting data from the first available source:
function fetchFromMultipleSources(url) {
const sources = [
fetch(`https://fast-cdn.com${url}`),
fetch(`https://backup-server.com${url}`),
fetch(`https://mirror-site.com${url}`)
];
return Promise.any(sources);
}
// Usage
fetchFromMultipleSources('/api/user-data')
.then(response => response.json())
.then(data => console.log('Data received from first available source:', data))
.catch(error => {
if (error instanceof AggregateError) {
console.error('All sources unavailable:', error.errors);
} else {
console.error('Error:', error);
}
});Useful when having multiple sources of the same data:
function fetchUserData(userId) {
const requests = [
fetch(`https://api1.example.com/users/${userId}`),
fetch(`https://api2.example.com/users/${userId}`),
fetch(`https://api3.example.com/users/${userId}`)
];
return Promise.any(requests)
.then(response => {
if (!response.ok) throw new Error('Network error');
return response.json();
});
}
// Usage
fetchUserData(123)
.then(userData => {
console.log('User data from the fastest API:', userData);
})
.catch(error => {
if (error instanceof AggregateError) {
console.error('All APIs unavailable:', error.errors);
}
});Can be used to check availability of the first working service:
function checkServiceAvailability() {
const services = [
fetch('https://service1.example.com/health'),
fetch('https://service2.example.com/health'),
fetch('https://service3.example.com/health')
];
return Promise.any(services)
.then(response => {
if (response.ok) {
return 'Service available';
} else {
throw new Error('Service not responding');
}
});
}
// Usage
checkServiceAvailability()
.then(status => console.log(status))
.catch(error => {
if (error instanceof AggregateError) {
console.log('All services unavailable');
}
});function fetchWithFallback(url, fallbackUrls, timeoutMs = 5000) {
const mainRequest = fetch(url);
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), timeoutMs);
});
const fallbackRequests = fallbackUrls.map(fbUrl => fetch(fbUrl));
// First wait for main request or timeout
return Promise.race([mainRequest, timeout])
.catch(() => {
// If main request failed, try fallbacks
return Promise.any(fallbackRequests);
});
}
// Usage
fetchWithFallback(
'/api/data',
['/api/data-backup1', '/api/data-backup2']
)
.then(response => response.json())
.then(data => console.log('Data:', data))
.catch(error => {
if (error instanceof AggregateError) {
console.error('All sources unavailable:', error.errors);
} else {
console.error('Error:', error.message);
}
});function fetchWithCachePreference(url) {
const cacheRequest = getCachedData(url).then(data => {
if (data) return data;
throw new Error('No data in cache');
});
const networkRequest = fetch(url).then(response => response.json());
return Promise.any([cacheRequest, networkRequest])
.catch(error => {
if (error instanceof AggregateError) {
// If neither cache nor network work, try network again
return networkRequest;
}
throw error;
});
}
// Usage
fetchWithCachePreference('/api/user-profile')
.then(data => {
console.log('Data received (first available source):', data);
return data;
})
.catch(error => {
if (error instanceof AggregateError) {
console.error('All sources unavailable:', error.errors);
}
});function fetchFromFastestWorkingAPI(endpoint) {
const apis = [
fetch(`https://api1.example.com${endpoint}`),
fetch(`https://api2.example.com${endpoint}`),
fetch(`https://api3.example.com${endpoint}`)
];
return Promise.any(apis)
.then(response => {
if (!response.ok) throw new Error('API error');
return response.json();
});
}
// Usage
fetchFromFastestWorkingAPI('/users/123')
.then(userData => {
console.log('User data from first working API:', userData);
})
.catch(error => {
if (error instanceof AggregateError) {
console.error('All APIs unavailable:', error.errors);
}
});If all promises are rejected, Promise.any() also rejects with AggregateError:
const errorPromise1 = new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 2000));
const errorPromise2 = new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 1000));
Promise.any([errorPromise1, errorPromise2])
.then(result => console.log('Result:', result))
.catch(error => {
if (error instanceof AggregateError) {
console.error('All promises failed:', error.errors);
} else {
console.error('Error:', error.message);
}
});If passed an empty array, Promise.any() rejects with AggregateError:
// ❌ Will be rejected
Promise.any([])
.then(result => console.log(result))
.catch(error => {
if (error instanceof AggregateError) {
console.error('Empty array of promises');
}
});
// ✅ Check for empty array
function safeAny(promises) {
if (promises.length === 0) {
return Promise.reject(new Error('No promises to process'));
}
return Promise.any(promises);
}Promise.any() converts non-promise values to resolved promises:
Promise.any([42, Promise.reject('Error'), new Promise(resolve => setTimeout(() => resolve(true), 1000))])
.then(result => console.log(result)); // 42 (number instantly converted to resolved promise)// ❌ May miss errors
Promise.any([fetch('/api/data1'), fetch('/api/data2')])
.then(data => console.log(data));
// ✅ Proper handling
Promise.any([fetch('/api/data1'), fetch('/api/data2')])
.then(response => {
if (!response.ok) throw new Error('Network error');
return response.json();
})
.then(data => console.log(data))
.catch(error => {
if (error instanceof AggregateError) {
console.error('All requests failed:', error.errors);
} else {
console.error('Error:', error);
}
});// ❌ Remaining promises continue executing
const promises = [slowOperation(), fastOperation()];
Promise.any(promises)
.then(result => {
console.log('Fast result:', result);
// slowOperation() still runs in background
});
// ✅ Cancel remaining operations (using AbortController)
const controller = new AbortController();
const signal = controller.signal;
const promises = [
fetch('/api/slow', { signal }),
fetch('/api/fast', { signal })
];
Promise.any(promises)
.then(response => {
controller.abort(); // Cancel other requests
return response.json();
})
.then(data => console.log(data));Promise.any() is a powerful tool for optimizing asynchronous operations, allowing you to select the first available successful result from multiple parallel operations, which is especially useful for implementing fallback data sources and speeding up data retrieval through multiple sources.
What will be output to the console and why?
const promise1 = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Error 1')), 100);
});
const promise2 = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Error 2')), 200);
});
const promise3 = new Promise(resolve => {
setTimeout(() => resolve('Success 3'), 300);
});
Promise.any([promise1, promise2, promise3])
.then(result => console.log('Result:', result))
.catch(error => {
if (error instanceof AggregateError) {
console.log('All failed:', error.errors.length);
} else {
console.log('Other error:', error.message);
}
});Answer: Result: Success 3
Explanation:
It’s important to understand that Promise.any() waits for the first successful result, not just the first completed one as in the case of Promise.race().
Want more articles to prepare for interviews? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪