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 уже "летит", но результат теряется// Безопасный вариант: обернуть каждый в .catchconst results = await Promise.all( ids.map(id => fetchUser(id).catch(e => ({ error: e.message, id }))));// Promise.allSettled — ждёт ВСЕ, никогда не rejectconst 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 → AggregateErrortry { 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 — “первый успешный”.