async/await в JavaScript

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

async/await — синтаксический сахар над промисами. Ключевое слово async перед функцией делает её асинхронной, а await внутри неё «приостанавливает» выполнение до разрешения промиса — без явных .then.

async-функция

Функция с async всегда возвращает промис. Если она возвращает обычное значение, оно автоматически оборачивается в Promise.resolve.

async function greet() {
  return 'Привет!';
}

greet().then(msg => console.log(msg)); // Привет!
console.log(greet()); // Promise { 'Привет!' }

Вывод:

Promise { 'Привет!' }
Привет!

await — ожидание промиса

await можно использовать только внутри async-функции. Он ждёт, пока промис разрешится, и возвращает его значение. Остальной код снаружи функции при этом не блокируется.

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function loadData() {
  console.log('Загрузка...');
  await delay(500);             // ждём 500 мс
  console.log('Данные загружены');
  return { items: [1, 2, 3] };
}

async function main() {
  const data = await loadData();
  console.log('Количество:', data.items.length);
}

main();

Вывод:

Загрузка...
Данные загружены
Количество: 3

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

Вместо .catch в цепочке промисов с async/await используют привычный try/catch. Если awaited-промис отклоняется, управление переходит в блок catch.

function fetchUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id === 1) resolve({ name: 'Аня' });
      else reject(new Error('Пользователь не найден'));
    }, 200);
  });
}

async function showUser(id) {
  try {
    const user = await fetchUser(id);
    console.log('Пользователь:', user.name);
  } catch (err) {
    console.log('Ошибка:', err.message);
  } finally {
    console.log('Запрос завершён');
  }
}

showUser(1);
showUser(99);

Вывод:

Пользователь: Аня
Запрос завершён
Ошибка: Пользователь не найден
Запрос завершён

Параллельное выполнение

Если написать два await подряд, запросы выполнятся последовательно (второй ждёт первого). Для параллельного запуска используют Promise.all.

function wait(ms, val) {
  return new Promise(r => setTimeout(() => r(val), ms));
}

async function sequential() {
  const a = await wait(300, 'A');
  const b = await wait(300, 'B');
  console.log(a, b); // ~600 мс суммарно
}

async function parallel() {
  const [a, b] = await Promise.all([wait(300, 'A'), wait(300, 'B')]);
  console.log(a, b); // ~300 мс суммарно
}

sequential();
parallel();

Вывод:

A B
A B

Не делайте await в цикле forEach — он не ждёт промисы. Используйте for...of или Promise.all с .map.

Коротко

  • async перед функцией делает её асинхронной; она всегда возвращает промис.
  • await приостанавливает выполнение внутри async-функции до разрешения промиса.
  • Ошибки обрабатывают через try/catch/finally — так же, как в синхронном коде.
  • Для параллельного запуска нескольких промисов используйте Promise.all.
Проверьте себя
1. Что возвращает async-функция, если явно вернуть число 42?
A42
BPromise, разрешённый в 42
Cundefined
Dnull
2. Где можно использовать ключевое слово await?
AВ любой функции
BТолько в async-функции
CТолько в конструкторе класса
DВ глобальном коде
3. Как правильно обрабатывать ошибку при await-вызове?
A.catch после await
Btry/catch вокруг await
CПроверить возвращаемое значение на null
Dawait автоматически обрабатывает ошибки
Поддержать проект