JS Tower
JavaScript & TypeScriptМодуль 5: Асинхронность

Методы Promise

Promise.all, allSettled, race и any

Цель урока

В этом уроке ты научишься:

  • Выполнять несколько промисов параллельно
  • Выбирать стратегию обработки результатов
  • Оптимизировать асинхронные операции

Promise.all

Ждёт выполнения всех промисов. Если один отклонён — весь результат отклонён.

let promise1 = Promise.resolve(1);
let promise2 = Promise.resolve(2);
let promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
  .then(results => console.log(results))
  .catch(error => console.log(error));

// [1, 2, 3]

При ошибке

let promise1 = Promise.resolve(1);
let promise2 = Promise.reject("Ошибка");
let promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
  .then(results => console.log(results))
  .catch(error => console.log(error));

// "Ошибка"

Практический пример

async function loadUserData(userId) {
  let [user, posts, comments] = await Promise.all([
    fetch(`/api/users/${userId}`).then(r => r.json()),
    fetch(`/api/posts?userId=${userId}`).then(r => r.json()),
    fetch(`/api/comments?userId=${userId}`).then(r => r.json())
  ]);
  
  return { user, posts, comments };
}

Promise.allSettled

Ждёт выполнения всех промисов, независимо от результата.

let promise1 = Promise.resolve(1);
let promise2 = Promise.reject("Ошибка");
let promise3 = Promise.resolve(3);

Promise.allSettled([promise1, promise2, promise3])
  .then(results => console.log(results));

// [
//   { status: "fulfilled", value: 1 },
//   { status: "rejected", reason: "Ошибка" },
//   { status: "fulfilled", value: 3 }
// ]

Фильтрация результатов

Promise.allSettled(promises)
  .then(results => {
    let successful = results
      .filter(r => r.status === "fulfilled")
      .map(r => r.value);
    
    let failed = results
      .filter(r => r.status === "rejected")
      .map(r => r.reason);
    
    console.log("Успешные:", successful);
    console.log("Неудачные:", failed);
  });

Promise.race

Возвращает результат первого завершённого промиса (успех или ошибка).

let slow = new Promise(resolve => setTimeout(() => resolve("Медленный"), 2000));
let fast = new Promise(resolve => setTimeout(() => resolve("Быстрый"), 1000));

Promise.race([slow, fast])
  .then(result => console.log(result));

// "Быстрый"

Таймаут запроса

function fetchWithTimeout(url, timeout) {
  let timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject("Таймаут"), timeout);
  });
  
  return Promise.race([fetch(url), timeoutPromise]);
}

fetchWithTimeout("/api/data", 5000)
  .then(response => response.json())
  .catch(error => console.log(error));

Promise.any

Возвращает первый успешный результат. Отклоняется только если все отклонены.

let promise1 = Promise.reject("Ошибка 1");
let promise2 = Promise.resolve("Успех");
let promise3 = Promise.reject("Ошибка 2");

Promise.any([promise1, promise2, promise3])
  .then(result => console.log(result));

// "Успех"

Все отклонены

let promise1 = Promise.reject("Ошибка 1");
let promise2 = Promise.reject("Ошибка 2");

Promise.any([promise1, promise2])
  .catch(error => console.log(error));

// AggregateError: All promises were rejected

Резервные источники

function fetchFromMultipleSources(urls) {
  let fetches = urls.map(url => fetch(url).then(r => r.json()));
  return Promise.any(fetches);
}

fetchFromMultipleSources([
  "https://api1.example.com/data",
  "https://api2.example.com/data",
  "https://api3.example.com/data"
])
  .then(data => console.log("Получено:", data))
  .catch(() => console.log("Все источники недоступны"));

Сравнение

МетодУспехОшибка
allВсе успешныПервая ошибка
allSettledВсе завершеныНикогда
raceПервый завершёнПервая ошибка
anyПервый успехВсе ошибки

Практика

Задание 1: Promise.all

Задача: Загрузи данные параллельно.

Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
[1,2,3]

Задание 2: Promise.allSettled

Задача: Обработай смешанные результаты.

Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
Успешных: 2
Неудачных: 1

Задание 3: Promise.race

Задача: Реализуй таймаут.

Loading...
Ваш вывод:

Проверь себя

  1. Когда использовать Promise.all vs Promise.allSettled?
  2. Чем Promise.race отличается от Promise.any?
  3. Как реализовать таймаут для запроса?