Promise.all, race, allSettled, any: работа с группой промисов
Зачем нужны методы для работы с группой промисов? 🤔
Представьте, что вы отправили несколько асинхронных запросов к API и хотите:
- Получить все ответы одновременно (
Promise.all) - Узнать, какой промис выполнится первым (
Promise.race) - Обработать результаты всех промисов, даже с ошибками (
Promise.allSettled) - Дождаться первого успешного промиса (
Promise.any)
Эти методы — мощные инструменты для управления асинхронным кодом. Разберём каждый на примерах!
Promise.all: «Все или ничего» 🎯
Ожидает выполнения всех промисов. Если хоть один отклонён — сразу возвращает ошибку.
const promises = [
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
];
Promise.all(promises)
.then(([users, posts, comments]) => {
console.log('Все данные загружены:', { users, posts, comments });
})
.catch(error => {
console.error('Один из запросов провалился:', error);
});
🔥 Важно: Порядок результатов соответствует порядку промисов в массиве, даже если они выполняются в разное время.
Promise.race: Гонка промисов 🏁
Возвращает результат первого завершившегося промиса (не важно, успешного или с ошибкой).
const timeout = ms => new Promise(
(_, reject) => setTimeout(() => reject('Timeout!'), ms)
);
const fetchData = fetch('/api/data');
Promise.race([fetchData, timeout(5000)])
.then(data => console.log('Данные получены:', data))
.catch(error => console.error('Ошибка или таймаут:', error));
💡 Идея: Часто используют для реализации таймаутов или выбора самого быстрого источника данных.
Promise.allSettled: Без исключений 🛡️
Ждёт завершения всех промисов и возвращает массив с результатами, включая ошибки.
const promises = [
Promise.resolve('Успех'),
Promise.reject('Ошибка'),
Promise.resolve('Ещё успех')
];
Promise.allSettled(promises)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Промис ${index}:`, result.value);
} else {
console.log(`Промис ${index} failed:`, result.reason);
}
});
});
📌 Особенность: Не имеет
.catch()— всегда «успешный» промис с массивом результатов.
Promise.any: Первый успешный 🏆
Ожидает первый успешно выполненный промис. Если все отклонены — возвращает AggregateError.
const apis = [
fetch('https://backup-api-1/data'),
fetch('https://backup-api-2/data'),
fetch('https://primary-api/data')
];
Promise.any(apis)
.then(data => console.log('Первый успешный ответ:', data))
.catch(errors => {
console.error('Все API упали:', errors.errors);
});
🚀 Сценарий: Отлично подходит для резервных API-вызовов — используем самый быстрый работающий источник.
Сравнение методов 📊
| Метод | Ждёт | Успех | Ошибка |
|---|---|---|---|
Promise.all |
Все | Массив всех результатов | Первая ошибка |
Promise.race |
Первый | Результат первого завершённого | Ошибка первого завершённого |
Promise.allSettled |
Все | Массив статусов всех промисов | Не бывает (всегда успех) |
Promise.any |
Первый успешный | Результат первого успешного | AggregateError (если все упали) |
Практика: Кейс из реальной жизни 💼
1. Параллельная загрузка изображений:
const loadImage = url => fetch(url).then(r => r.blob());
Promise.all([
loadImage('cat.jpg'),
loadImage('dog.jpg')
]).then(blobs => {
blobs.forEach(blob => {
const img = new Image();
img.src = URL.createObjectURL(blob);
document.body.append(img);
});
});