Ответ
При разработке и тестировании асинхронного кода на JavaScript я использую эти методы для разных сценариев параллельного выполнения промисов. Их поведение при успехе и ошибке кардинально различается.
Promise.all(iterable)
- Логика: Ожидает успешного завершения ВСЕХ промисов в переданном массиве (или итерируемом объекте).
- Успех: Возвращает массив результатов в том же порядке, что и исходные промисы.
- Неудача: Немедленно отклоняется с причиной (error) первого отклоненного промиса. Остальные промисы продолжают выполняться, но их результаты игнорируются.
- Аналогия: Групповой заказ: еда подается только когда готовы все блюда. Если одно блюдо испорчено (отклонен промис), весь заказ отменяется.
// Пример: параллельная загрузка нескольких конфигурационных файлов
const loadUserConfig = fetch('/api/config/user.json').then(r => r.json());
const loadAppConfig = fetch('/api/config/app.json').then(r => r.json());
async function initializeApp() {
try {
// Оба конфига необходимы для старта приложения
const [userConfig, appConfig] = await Promise.all([loadUserConfig, loadAppConfig]);
console.log('Оба конфига загружены:', userConfig, appConfig);
startApp(userConfig, appConfig);
} catch (error) {
// Если хотя бы один fetch упадет с 404, мы попадем сюда
console.error('Не удалось загрузить конфигурацию:', error);
showErrorScreen();
}
}
Promise.any(iterable)
- Логика: Ожидает успешного завершения ПЕРВОГО успешного промиса.
- Успех: Возвращает значение первого успешно выполнившегося промиса.
- Неудача: Отклоняется только если отклонены ВСЕ промисы в переданном массиве. Возвращает объект
AggregateError, содержащий массив всех ошибок. - Аналогия: Поиск запчасти: обзваниваем несколько поставщиков. Нам нужна деталь от того, кто ответит первым и скажет "есть в наличии". Ошибка ("нет в наличии") нас не пугает, пока есть другие поставщики. Провал наступает только если все сказали "нет".
// Пример: резервирование источников данных (primary, secondary, fallback)
const primaryDataSource = fetchFromPrimaryAPI().catch(() => { throw new Error('Primary failed'); });
const secondaryDataSource = fetchFromSecondaryAPI().catch(() => { throw new Error('Secondary failed'); });
const fallbackDataSource = fetchFromCache().catch(() => { throw new Error('Cache failed'); });
async function getCriticalData() {
try {
// Нам нужны данные хотя бы из одного источника
const data = await Promise.any([primaryDataSource, secondaryDataSource, fallbackDataSource]);
console.log('Данные получены из первого доступного источника:', data);
return data;
} catch (aggregateError) {
// Сюда попадем, только если ВСЕ три источника отказали
console.error('Все источники данных недоступны:', aggregateError.errors);
throw new Error('Service unavailable');
}
}
Сравнительная таблица
| Метод | Ждет... | Возвращает при успехе | Возвращает при ошибке | Типичный use-case |
|---|---|---|---|---|
Promise.all() |
Всех | Массив результатов | Ошибку первого отклоненного | Параллельная загрузка взаимозависимых данных. |
Promise.any() |
Первого успешного | Результат первого успешного | AggregateError (если все упали) |
Резервирование, выбор самого быстрого источника. |
Выбор инструмента:
- Использую
Promise.all(), когда для продолжения работы нужны результаты всех операций (например, инициализация модулей). - Использую
Promise.any(), когда достаточно результата любой одной успешной операции из набора альтернатив (например, запрос к нескольким CDN за одним ресурсом).