← Назад к вопросам
Продолжит ли работу Promise.all если какая-либо ветка запросов упадет
2.2 Middle🔥 251 комментариев
#Node.js и JavaScript
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Promise.all и обработка ошибок
Нет, Promise.all остановится и вернет rejected Promise при первой ошибке, даже если остальные Promise"ы еще выполняются. Это важный аспект асинхронного программирования в JavaScript/Node.js, который часто упускают на собеседованиях.
Как это работает
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Ошибка в promise2")), 100);
});
const promise3 = new Promise((resolve) => {
setTimeout(() => resolve(10), 200);
});
Promise.all([promise1, promise2, promise3])
.then(values => console.log(values)) // НЕ выполнится
.catch(error => console.error(error)); // Выполнится: Error: Ошибка в promise2
Результат:
Error: Ошибка в promise2
Обратите внимание: promise3 мог успешно разрешиться за 200ms, но Promise.all уже упал после ошибки в promise2 на 100ms.
Демонстрация с API запросами
// Реальный сценарий: загрузка данных пользователя, продуктов и комментариев
async function fetchUserData(userId: string) {
const responses = await Promise.all([
fetch(`/api/users/${userId}`), // успех
fetch(`/api/products`), // ошибка 500
fetch(`/api/comments/${userId}`) // успех (но не выполнится)
]);
return Promise.all(responses.map(r => r.json()));
}
// При вызове:
try {
const data = await fetchUserData("123");
console.log(data);
} catch (error) {
// Попадем сюда при ошибке в /api/products
console.error("Ошибка загрузки данных:", error);
// /api/comments никогда не будет загружен, хотя он может быть еще в процессе
}
Альтернативы для разных сценариев
1. Promise.allSettled — для того чтобы дождаться всех Promise"ов
const results = await Promise.allSettled([
fetch("/api/users/123"),
fetch("/api/products"),
fetch("/api/comments")
]);
// Результат:
// [
// { status: "fulfilled", value: Response },
// { status: "rejected", reason: Error },
// { status: "fulfilled", value: Response }
// ]
const successful = results.filter(r => r.status === "fulfilled");
const failed = results.filter(r => r.status === "rejected");
console.log(`Успешно: ${successful.length}, Ошибок: ${failed.length}`);
2. Promise.race — для получения первого результата
const firstResult = await Promise.race([
fetch("/api/users", { timeout: 5000 }),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), 5000)
)
]);
// Кто-нибудь завершится первым (успех или ошибка)
3. Try-catch с обработкой ошибок на уровне каждого Promise"а
const [userData, products, comments] = await Promise.all([
fetch("/api/users/123")
.then(r => r.json())
.catch(error => {
console.error("Ошибка загрузки пользователя:", error);
return null; // Не прерываем Promise.all
}),
fetch("/api/products")
.then(r => r.json())
.catch(error => {
console.error("Ошибка загрузки продуктов:", error);
return []; // Возвращаем пустой массив вместо ошибки
}),
fetch("/api/comments")
.then(r => r.json())
.catch(error => {
console.error("Ошибка загрузки комментариев:", error);
return []; // Не прерываем общий поток
})
]);
console.log(userData, products, comments);
// Все три запроса выполнятся, даже если какие-то упадут
Лучшая практика: обработка ошибок в Promise.all
async function loadUserDashboard(userId: string) {
try {
// Группируем критичные и некритичные запросы
const [user, posts] = await Promise.all([
fetch(`/api/users/${userId}`).then(r => r.json()),
fetch(`/api/users/${userId}/posts`).then(r => r.json())
]);
// Некритичные данные загружаем отдельно
const recommendations = await fetch(`/api/recommendations/${userId}`)
.then(r => r.json())
.catch(error => {
console.warn("Рекомендации недоступны:", error);
return [];
});
return { user, posts, recommendations };
} catch (error) {
throw new DashboardLoadError(
`Не удалось загрузить данные пользователя: ${error.message}`
);
}
}
Тестирование этого поведения
describe("Promise.all error handling", () => {
it("should reject when any promise rejects", async () => {
const promises = [
Promise.resolve(1),
Promise.reject(new Error("fail")),
Promise.resolve(3)
];
await expect(Promise.all(promises)).rejects.toThrow("fail");
});
it("should complete all with allSettled", async () => {
const promises = [
Promise.resolve(1),
Promise.reject(new Error("fail")),
Promise.resolve(3)
];
const results = await Promise.allSettled(promises);
expect(results).toHaveLength(3);
expect(results[1].status).toBe("rejected");
});
});
Ключевые выводы
- Promise.all: прерывается при первой ошибке (fail-fast)
- Promise.allSettled: дождется всех, вернет массив результатов
- Обработка: используй
.catch()на каждом Promise для критичных операций - Рекомендация: разделяй критичные и некритичные запросы на разные
Promise.all