← Назад к списку
ТехническаяFrontendJunior

Что такое промисы и чем async/await отличается от цепочек then?

Короткий ответ

  • Промис — объект-обёртка над будущим результатом операции
  • Три состояния: pending, fulfilled, rejected; переход необратим
  • then возвращает новый промис, поэтому цепочки работают
  • async-функция всегда возвращает промис
  • await приостанавливает функцию, не блокируя поток
  • Ошибки ловятся через catch или try/catch с await
  • Параллельность: Promise.all, allSettled, race, any

async/await — синтаксис поверх тех же промисов, который делает асинхронный код линейным и позволяет обрабатывать ошибки привычным try/catch.

Как сказать вслух

пример ответа

Промис — это объект, который представляет результат операции, которая завершится позже: запрос к серверу, таймер. У него есть состояния — ожидание, успех и ошибка. async/await — это не другой механизм, а удобная запись тех же промисов: await ждёт результат, но поток при этом не блокируется, движок продолжает обрабатывать другие события. Ошибки при этом ловятся обычным try/catch, что сильно упрощает чтение кода.

Подробный ответ

Основной ответ

Промис стартует в состоянии pending и один раз переходит либо в fulfilled со значением, либо в rejected с причиной. Подписка через then/catch/finally возвращает новый промис, что позволяет строить цепочки и трансформировать результат. async/await — синтаксический сахар: async-функция возвращает промис, а await разворачивает значение промиса, приостанавливая выполнение функции до его завершения; продолжение ставится в очередь микрозадач. Главные выигрыши — линейный код без вложенных колбэков, обычный try/catch/finally для ошибок, понятные условия и циклы вокруг асинхронных вызовов. Важно не терять параллелизм: последовательные await независимых запросов замедляют код, независимые операции запускают сразу и ждут через Promise.all, а частичные отказы обрабатывают через allSettled.

Ключевые моменты

  • Один переход состояния. Промис нельзя «перерешать»: после fulfilled или rejected результат зафиксирован навсегда.
  • await и поток. await приостанавливает только текущую async-функцию; главный поток свободен для других задач.
  • Обработка ошибок. Непойманный reject даёт unhandledrejection; нужен catch в конце цепочки или try/catch вокруг await.
  • Комбинаторы. Promise.all падает при первой ошибке, allSettled ждёт всех, race и any — про первый результат.

Практический контекст

Это ежедневный инструмент: запросы через fetch, загрузка данных в эффектах, очереди операций. На собеседовании любят спрашивать разницу между последовательными await и Promise.all, а также что произойдёт с ошибкой без catch. Хороший кандидат упоминает и отмену через AbortController, потому что сами промисы отменять нельзя — это частая реальная задача при переключении между экранами.

Пример кода

// Медленно: запросы идут по очереди
const a = await fetchUser(1);
const b = await fetchUser(2);

// Быстро: запускаем сразу, ждём вместе
const [u1, u2] = await Promise.all([fetchUser(1), fetchUser(2)]);

Частые ошибки

  • Пишут await в цикле для независимых запросов, теряя параллельность
  • Считают, что await блокирует весь поток, а не только текущую функцию
  • Забывают обрабатывать reject, получая unhandledrejection в проде

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru