← Назад к вопросам

Что такое Promise.all?

1.0 Junior🔥 261 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Promise.all: параллельное выполнение Promise'ов

Что такое Promise.all

Promise.all это метод, который принимает массив Promise'ов и возвращает новый Promise. Результат:

  • Успех: все Promise'ы resolve — возвращает массив результатов
  • Ошибка: хотя бы один Promise reject — весь Promise.all reject'ится

Синтаксис и примеры

// Базовый пример
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3]).then(results => {
  console.log(results); // [1, 2, 3]
});

// С async/await
const results = await Promise.all([p1, p2, p3]);
console.log(results); // [1, 2, 3]

Практический пример: Загрузка данных из разных API

// Без Promise.all — последовательно (медленно)
const getUserProfile = async (userId) => {
  const user = await fetch(`/api/users/${userId}`).then(r => r.json()); // 200ms
  const posts = await fetch(`/api/posts/${userId}`).then(r => r.json()); // 200ms
  const friends = await fetch(`/api/friends/${userId}`).then(r => r.json()); // 200ms
  // Total: 600ms
  return { user, posts, friends };
};

// С Promise.all — параллельно (быстро)
const getUserProfileFast = async (userId) => {
  const [user, posts, friends] = await Promise.all([
    fetch(`/api/users/${userId}`).then(r => r.json()),
    fetch(`/api/posts/${userId}`).then(r => r.json()),
    fetch(`/api/friends/${userId}`).then(r => r.json())
  ]);
  // Total: 200ms (самый долгий запрос)
  return { user, posts, friends };
};

Обработка ошибок

// Если один Promise reject'ится — весь Promise.all reject'ится
const p1 = Promise.resolve(1);
const p2 = Promise.reject(new Error('Oops!'));
const p3 = Promise.resolve(3);

try {
  const results = await Promise.all([p1, p2, p3]);
  console.log(results); // Это НЕ выполнится
} catch (error) {
  console.error(error.message); // "Oops!"
}

Реальный пример: Инициализация приложения

const initializeApp = async () => {
  try {
    const [db, cache, config] = await Promise.all([
      connectToDatabase(),    // 500ms
      initializeRedis(),      // 200ms
      loadConfiguration()     // 100ms
    ]);
    // Total: 500ms (самый долгий)
    
    console.log('App initialized');
    return { db, cache, config };
  } catch (error) {
    console.error('Initialization failed:', error);
    process.exit(1);
  }
};

Promise.all с разными типами данных

const mixed = await Promise.all([
  Promise.resolve(1),
  'string', // не Promise, используется как есть
  new Promise(resolve => setTimeout(() => resolve('delayed'), 100)),
  42 // не Promise
]);

console.log(mixed); // [1, 'string', 'delayed', 42]

Promise.allSettled — когда ошибка не критична

// Promise.all — если один упал, все упали
const all = await Promise.all([
  fetchUser(),     // resolve
  fetchPosts(),    // reject
  fetchComments()  // resolve (но не выполнится)
]);
// Ошибка!

// Promise.allSettled — выполняет ВСЕ и возвращает результаты
const results = await Promise.allSettled([
  fetchUser(),     // resolve
  fetchPosts(),    // reject
  fetchComments()  // resolve (выполнится)
]);

// Результат:
[
  { status: 'fulfilled', value: {...} },
  { status: 'rejected', reason: Error(...) },
  { status: 'fulfilled', value: [...] }
]

// Обработка результатов
const successful = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value);

Promise.race — кто первый выполнится

// Promise.race возвращает результат первого выполненного Promise'а
const fastest = await Promise.race([
  fetchFromServer1(), // 300ms
  fetchFromServer2(), // 200ms (первый!)
  fetchFromServer3()  // 400ms
]);

console.log(fastest); // Результат от Server2

// Практический пример: timeout
const fetchWithTimeout = (url, timeout = 5000) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
};

const data = await fetchWithTimeout('/api/data', 3000); // Если дольше 3 сек — ошибка

Promise.any — хотя бы один успех

// Promise.any — возвращает первый успешный результат
const first = await Promise.any([
  Promise.reject('Server 1 down'),
  Promise.resolve('Server 2 up'), // первый успешный
  Promise.reject('Server 3 down')
]);

console.log(first); // 'Server 2 up'

// Если все reject'ятся — ошибка
const none = await Promise.any([
  Promise.reject('A'),
  Promise.reject('B')
]);
// AggregateError: All promises were rejected

Отличия методов параллельного выполнения

Promise.all:
- Возвращает результаты всех Promise'ов в массиве
- Если один reject'ится — весь all reject'ится
- Использование: когда все результаты нужны

Promise.allSettled:
- Возвращает статусы всех Promise'ов (fulfilled/rejected)
- Не зависит от ошибок других
- Использование: когда нужно обработать все, даже ошибки

Promise.race:
- Возвращает результат первого выполненного Promise
- Использование: timeout, выбор самого быстрого

Promise.any:
- Возвращает результат первого успешного Promise
- Использование: redundancy, fail-over

Примеры из production кода

// 1. Инициализация сервисов
const startServer = async () => {
  const [database, cache, messageQueue] = await Promise.all([
    db.connect(),
    redis.connect(),
    rabbitmq.connect()
  ]);
};

// 2. Загрузка данных в dashboards
const getDashboardData = async (userId) => {
  const [stats, analytics, recommendations] = await Promise.all([
    getUserStats(userId),
    getAnalytics(userId),
    getRecommendations(userId)
  ]);
  return { stats, analytics, recommendations };
};

// 3. Batch операции
const updateMultipleUsers = async (userIds) => {
  const updatePromises = userIds.map(id =>
    updateUser(id, { lastSeen: Date.now() })
  );
  await Promise.all(updatePromises);
};

// 4. С обработкой ошибок
const loadUserData = async (userId) => {
  try {
    const [user, profile, settings] = await Promise.all([
      getUserFromDB(userId),
      getUserProfile(userId),
      getUserSettings(userId)
    ]);
    return { user, profile, settings };
  } catch (error) {
    if (error.code === 'USER_NOT_FOUND') {
      return null;
    }
    throw error;
  }
};

Как НЕ использовать

// ❌ ПЛОХО: создавать Promise'ы после Promise.all
for (let i = 0; i < users.length; i++) {
  const user = await getUser(users[i]); // Последовательно!
}

// ✅ ХОРОШО: создавать Promise'ы до Promise.all
const userPromises = users.map(id => getUser(id));
const allUsers = await Promise.all(userPromises); // Параллельно

// ❌ ПЛОХО: забывать await
Promise.all([...]) // Не дожидаемся результата!

// ✅ ХОРОШО
await Promise.all([...]) // Ждём результата

Заключение

Promise.all это фундаментальная концепция асинхронного программирования:

  • Для параллельного выполнения независимых операций
  • Существенно ускоряет приложение
  • Нужно правильно обрабатывать ошибки
  • Есть варианты (allSettled, race, any) для разных случаев