IT и код

Что такое async/await в JavaScript

⏱ 5 мин чтения👁 …Обновлено 30 июля 2026ИнфоЗал · База знаний

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

Как это выглядит

async function loadUser(id) {
  const res = await fetch('/api/users/' + id);
  const user = await res.json();
  return user;
}

Слово async перед функцией означает, что она всегда возвращает промис. Слово await внутри неё приостанавливает выполнение до получения результата, не блокируя браузер. Сравните с записью через цепочку методов: логика та же, но читается сверху вниз, без вложенности.

Ключевое заблуждение: await не останавливает страницу. Он приостанавливает только текущую функцию, а браузер в это время обрабатывает нажатия, анимации и другие задачи. Останавливает всё как раз синхронный код — например, тяжёлый цикл.

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

Главное удобство — обычный try/catch вместо отдельного обработчика:

async function loadUser(id) {
  try {
    const res = await fetch('/api/users/' + id);
    if (!res.ok) throw new Error('HTTP ' + res.status);
    return await res.json();
  } catch (e) {
    console.error('Не удалось загрузить:', e);
    return null;
  }
}

Обратите внимание на проверку res.ok: функция fetch не считает ошибкой ответы 404 и 500 — она отклоняет промис только при сетевом сбое. Код состояния нужно проверять руками, иначе вы будете разбирать страницу с ошибкой как JSON.

Последовательно или параллельно

Типичная ошибка производительности — ждать запросы по очереди, когда они независимы:

// медленно: 300 мс, если каждый по 100
const a = await getA();
const b = await getB();
const c = await getC();

// быстро: 100 мс
const [a, b, c] = await Promise.all([getA(), getB(), getC()]);

Правило простое: если результат одного запроса нужен для следующего — только последовательно. Если запросы независимы — всегда через Promise.all.

МетодПоведение
Promise.allЖдёт все, падает целиком при первой ошибке
Promise.allSettledЖдёт все и возвращает результат каждого, включая ошибки
Promise.raceВозвращает первый завершившийся, любой
Promise.anyВозвращает первый успешный

Где await не сработает как ожидается

  • Внутри forEach. Этот метод не ждёт промисы: цикл пролетит мгновенно. Используйте обычный for...of.
  • В обработчике события без async. Функцию нужно объявить асинхронной, иначе await — синтаксическая ошибка.
  • Без обработки отклонения. Асинхронная функция, вызванная без await и без catch, проглотит ошибку молча.
  • В конструкторе класса. Он не может быть асинхронным — выносите загрузку в отдельный метод.

Как правильно перебрать список

// последовательно
for (const id of ids) {
  const user = await loadUser(id);
  console.log(user);
}

// параллельно
const users = await Promise.all(ids.map(loadUser));

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

  • Забывают await и получают промис вместо данных — отсюда классическое undefined при обращении к полю.
  • Ждут независимые запросы по очереди и утраивают время загрузки.
  • Не проверяют res.ok и разбирают страницу ошибки как JSON.
  • Используют await внутри forEach.
  • Оставляют асинхронные вызовы без обработки ошибок.

Что запомнить

Async делает функцию возвращающей промис, await ждёт результат, не блокируя браузер. Ошибки ловятся обычным try/catch, но код состояния HTTP нужно проверять вручную. Независимые запросы запускайте через Promise.all, а для перебора с ожиданием берите for...of, а не forEach. Пропущенный await — причина большинства странных undefined.

Коротко: вопросы и ответы

Можно ли использовать await на верхнем уровне? Да, в модулях это разрешено. В обычном скрипте нужно обернуть код в асинхронную функцию.

Async/await быстрее промисов? Это тот же механизм, только другой синтаксис. Разница лишь в читаемости.

Как сделать паузу? Обернуть setTimeout в промис и дождаться его: await new Promise(r => setTimeout(r, 1000)).

Была ли статья полезной?
Реклама

Комментарии