async/await

Самый удобный способ писать асинхронный код — как будто он синхронный.

async/await — это синтаксис поверх промисов: await «ждёт» результат промиса, а код выглядит линейно, как обычный.

Та же логика, но читается линейно

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

Функцию помечают словом async, а внутри неё перед промисом ставят await — выполнение «приостановится» на этой строке, пока промис не разрешится:

function delay(value) {
  return Promise.resolve(value);
}

async function run() {
  const a = await delay(10);
  const b = await delay(a + 5);
  const c = await delay(b + 5);
  console.log("Результат:", c);
}

run();

Вывод:

Результат: 20

Никаких .then — каждая строка ждёт предыдущую. Читается как обычная последовательность шагов.

Обработка ошибок через try/catch

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

async function risky() {
  return Promise.reject(new Error("что-то сломалось"));
}

async function main() {
  try {
    await risky();
  } catch (err) {
    console.log("Поймали ошибку:", err.message);
  }
  console.log("Программа продолжает работу");
}

main();

Вывод:

Поймали ошибку: что-то сломалось
Программа продолжает работу

async-функция всегда возвращает промис

Под капотом async/await — это всё те же промисы, просто с приятным синтаксисом: движок сам разворачивает их за вас. Поэтому два стиля полностью совместимы. Результат async-функции можно дождаться как через await, так и через .then, а внутри async-функции можно вызывать обычные функции, возвращающие промис.

Важный момент: что бы вы ни вернули из async-функции, наружу выйдет промис. Поэтому её результат тоже забирают через await или .then:

async function getNumber() {
  return 42; // обернётся в промис автоматически
}

async function show() {
  const n = await getNumber();
  console.log("Число:", n);
}

show();

Вывод:

Число: 42

Параллельность не теряем

Если писать await подряд, операции пойдут последовательно. Когда они независимы, лучше запустить их сразу и дождаться через Promise.all:

async function loadAll() {
  // запускаем все три сразу, ждём вместе
  const [a, b, c] = await Promise.all([
    Promise.resolve("A"),
    Promise.resolve("B"),
    Promise.resolve("C")
  ]);
  console.log(a, b, c);
}

loadAll();

Вывод:

A B C

Эволюция асинхронности

ПодходМинус
Колбэкиcallback hell, ручная обработка ошибок
Промисыцепочки .then многословны
async/awaitпочти нет — это рекомендуемый стиль

Итог

  • async помечает функцию, await ждёт результат промиса внутри неё.
  • Код выглядит линейно, как синхронный, но не блокирует поток.
  • Ошибки ловят обычным try/catch.
  • Для параллельных задач сочетают await с Promise.all.
Проверьте себя
1. Что делает оператор await?
AБлокирует весь поток Node
BПриостанавливает async-функцию до разрешения промиса
CСоздаёт новый промис
DОтменяет операцию
2. Чем ловят ошибки при использовании await?
A.catch обязательно
Btry/catch
Cif (err)
DonError
3. Что возвращает любая async-функция?
AТо, что в return, как есть
BВсегда промис
Cundefined
DКолбэк
Поддержать проект