Ответ
В Node.js для параллельного выполнения независимых асинхронных операций я использую Promise.all(). Это позволяет запустить все промисы одновременно и дождаться их завершения.
Базовый пример с HTTP-запросами:
const axios = require('axios');
async function fetchMultipleAPIs(urls) {
const promises = urls.map(url => axios.get(url));
try {
const responses = await Promise.all(promises);
return responses.map(res => res.data);
} catch (error) {
// Если один запрос падает, падает весь Promise.all
console.error('One of the requests failed:', error);
throw error;
}
}
// Использование
const apiEndpoints = [
'https://api.example.com/users',
'https://api.example.com/posts',
'https://api.example.com/comments'
];
const data = await fetchMultipleAPIs(apiEndpoints);
console.log('All data fetched:', data);
Когда нужна обработка ошибок без прерывания:
async function fetchWithSettled(urls) {
const promises = urls.map(async (url) => {
try {
const response = await axios.get(url);
return { status: 'fulfilled', value: response.data };
} catch (error) {
return { status: 'rejected', reason: error.message };
}
});
return await Promise.all(promises);
}
// Или используем встроенный Promise.allSettled (Node.js 12.9.0+)
const results = await Promise.allSettled(promises);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
Важные моменты из моего опыта:
Promise.all()оптимален для I/O операций (запросы к БД, API, файлы)- Для CPU-intensive задач лучше использовать worker threads
- Всегда ограничиваю количество параллельных запросов к внешним API (например, с помощью
p-limit) - При работе с базой данных иногда эффективнее использовать один сложный запрос вместо нескольких параллельных
Ответ 18+ 🔞
Слушай, а вот реально полезная штука, которую я в работе постоянно юзаю — Promise.all(). Ну ты представляешь, сколько времени можно сэкономить, когда тебе надо кучу асинхронных операций запустить параллельно, а не ждать, пока каждая предыдущая ебется как последняя? Это просто волшебство, ёпта.
Вот смотри, простой пример с запросами по API:
const axios = require('axios');
async function fetchMultipleAPIs(urls) {
const promises = urls.map(url => axios.get(url));
try {
const responses = await Promise.all(promises);
return responses.map(res => res.data);
} catch (error) {
// Если один запрос падает, падает весь Promise.all
console.error('One of the requests failed:', error);
throw error;
}
}
// Использование
const apiEndpoints = [
'https://api.example.com/users',
'https://api.example.com/posts',
'https://api.example.com/comments'
];
const data = await fetchMultipleAPIs(apiEndpoints);
console.log('All data fetched:', data);
Но тут есть один нюанс, который многих накрывает медным тазом: если хоть один промис вылетает с ошибкой — весь Promise.all() летит в пизду. Представь, ты делаешь пять запросов, четыре уже отработали, а пятый — херак — 500 ошибка. И всё, приехали, никаких данных не получишь, хотя четыре-то уже готовы. Обидно, блядь.
Поэтому иногда надо обрабатывать ошибки аккуратнее, чтобы не прерывать всё к хуям:
async function fetchWithSettled(urls) {
const promises = urls.map(async (url) => {
try {
const response = await axios.get(url);
return { status: 'fulfilled', value: response.data };
} catch (error) {
return { status: 'rejected', reason: error.message };
}
});
return await Promise.all(promises);
}
// Или используем встроенный Promise.allSettled (Node.js 12.9.0+)
const results = await Promise.allSettled(promises);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
Вот Promise.allSettled() — это вообще песня, он ждёт ВСЕ промисы, неважно, упали они или нет, и потом отдаёт массив с результатами. Удобно, когда тебе важно получить хоть что-то, а не нихуя.
А теперь про важные моменты, которые я на своей шкуре прочувствовал:
-
Promise.all()— это овердохуища для I/O операций. Запросы к API, чтение файлов, обращения к базе — всё это он распараллеливает на ура. Скорость вырастает в разы, особенно когда операции независимые. -
Но если у тебя CPU-intensive задачи (типа сложных вычислений, шифрования, обработки изображений), то тут
Promise.all()не поможет — Node.js всё равно будет выполнять их в одном потоке, по очереди. Для такого дела уже worker threads нужны, иначе производительность будет пиздец какая низкая. -
Всегда ограничивай количество параллельных запросов к внешним API, а то наткнёшься на лимиты или тебя забанит сервис за DDoS. Я обычно
p-limitставлю, чтобы не больше 5-10 запросов одновременно летело. Иначе можно получить бан, а потом сидеть и думать, какого хуя ничего не работает. -
И ещё момент с базами данных: иногда один сложный JOIN-запрос будет быстрее, чем десять параллельных простых запросов через
Promise.all(). База — она тоже не железная, у неё свои ограничения. Так что думай головой, а не тупо всё параллель запускай.
В общем, инструмент мощный, но как любая мощная штука — требует мозгов. Иначе можно такого наворотить, что потом полдня будешь дебажить, почему всё падает.