Перейти к содержимому

Promise.all / allSettled / race / any

Четыре статических комбинатора Promise покрывают все стратегии параллельного ожидания: fail-fast (all, race), no-fail (allSettled) и first-success (any) — на собесе нужно знать семантику каждого и edge cases с пустыми массивами.

// Promise.all — fail-fast: первый reject → reject всего
const [user, posts] = await Promise.all([
fetchUser(1), // ~100ms
fetchPosts(1), // ~200ms
]); // завершится через ~200ms (наибольшее)
// Если fetchUser бросает — fetchPosts уже "летит", но результат теряется
// Безопасный вариант: обернуть каждый в .catch
const results = await Promise.all(
ids.map(id => fetchUser(id).catch(e => ({ error: e.message, id })))
);
// Promise.allSettled — ждёт ВСЕ, никогда не reject
const results = await Promise.allSettled([
Promise.resolve(1),
Promise.reject('err'),
Promise.resolve(3),
]);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'err' },
// { status: 'fulfilled', value: 3 },
// ]
const ok = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
// Promise.race — первый settled (fulfilled ИЛИ rejected)
const timeout = ms => new Promise((_, r) =>
setTimeout(() => r(new Error(`timeout ${ms}ms`)), ms));
const result = await Promise.race([
fetch('/api/data'),
timeout(3000),
]).catch(e => { throw new Error('Request timed out: ' + e.message); });
// Promise.any — первый FULFILLED; все reject → AggregateError
try {
const fastest = await Promise.any([
fetch('https://cdn1.example.com/data'),
fetch('https://cdn2.example.com/data'),
fetch('https://cdn3.example.com/data'),
]);
} catch (e) {
if (e instanceof AggregateError) console.log('All CDNs failed:', e.errors);
}

Итог: Выбор комбинатора определяется стратегией отказа: all — “все или ничего”; allSettled — “дождаться всех невзирая на ошибки”; race — “первый финишировавший”; any — “первый успешный”.