Learn JavaScript

await - ожидание результата промиса в JavaScript

await в JavaScript используют, чтобы дождаться результата промиса и получить уже готовое значение без цепочки then(). Обычно await применяют внутри async-функций.

Главная идея простая: await временно останавливает выполнение текущей асинхронной функции, пока выражение справа не даст результат, а потом возвращает это значение дальше в код.

Синтаксис

Базовая запись выглядит так:

const value = await expression;

Где:

  • expression - чаще всего промис, но это может быть и обычное значение

Обычно await используют так:

async function fn() {
  const result = await Promise.resolve(42);
  console.log(result);
}

Где можно использовать await

Чаще всего await используют внутри async-функций.

async function loadData() {
  const result = await fetch("/api/data");
  return result;
}

Также await можно использовать на верхнем уровне модуля.

const data = await Promise.resolve("ok");
console.log(data);

Но это работает именно в модулях, а не в любом произвольном скрипте.

Что возвращает await

await сам по себе не возвращает Promise. Он возвращает уже готовый результат выражения.

Если справа был успешно завершённый промис, await даст его значение.

async function fn() {
  const value = await Promise.resolve(42);
  console.log(value); // 42
}

fn();

То есть после await вы обычно работаете уже не с промисом, а с готовыми данными.

Простой пример

async function getMessage() {
  const message = await Promise.resolve("Привет");
  console.log(message); // "Привет"
}

getMessage();

Такой код читается ближе к обычному пошаговому сценарию.

await ждёт Promise и отдаёт его результат

Это основное поведение.

async function fn() {
  const user = await fetch("/api/user");
  console.log(user);
}

Пока промис от fetch(...) не завершится, выполнение текущей async-функции дальше не пойдёт.

await работает и с обычными значениями

Это полезный нюанс.

Если справа не промис, а обычное значение, await просто вернёт его как есть.

async function fn() {
  const value = await 42;
  console.log(value); // 42
}

fn();

Это не вызывает ошибку.

Даже await обычного значения продолжает код асинхронно

Это важный момент, который часто упускают.

console.log("start");

async function fn() {
  console.log("before await");
  await 42;
  console.log("after await");
}

fn();

console.log("end");

Результат будет таким:

start
before await
end
after await

Хотя 42 уже готово сразу, код после await всё равно продолжится не мгновенно в ту же строку.

await не блокирует весь код целиком

Это особенно важно понимать правильно.

await останавливает не весь JavaScript и не всю программу, а только текущую async-функцию или модульный участок, в котором он стоит.

async function fn() {
  console.log("before");
  await new Promise((resolve) => setTimeout(resolve, 20));
  console.log("after");
}

fn();
console.log("outside");

Результат будет таким:

before
outside
after

Пока одна асинхронная функция ждёт, остальной код продолжает работать.

Если промис завершился с ошибкой, await выбросит её

Это ключевой момент.

Если справа отклонённый промис, await не вернёт значение, а выбросит ошибку.

async function fn() {
  try {
    await Promise.reject(new Error("boom"));
  } catch (error) {
    console.log(error.message); // "boom"
  }
}

fn();

Поэтому await очень часто используют вместе с try...catch.

Ошибки с await удобно ловить через try...catch

Это один из главных практических плюсов связки async и await.

async function loadUser() {
  try {
    const response = await fetch("/api/user");
    const user = await response.json();

    return user;
  } catch (error) {
    console.log("Ошибка загрузки:", error);
    throw error;
  }
}

Такой код обычно читается проще, чем длинная цепочка из then() и catch().

Несколько await подряд выполняются последовательно

Это полезно помнить в реальном коде.

async function fn() {
  const a = await fetch("/api/a");
  const b = await fetch("/api/b");

  console.log(a, b);
}

Здесь второй запрос начнётся только после завершения первого.

Если операции независимы друг от друга, часто лучше запускать их параллельно и потом ждать вместе:

async function fn() {
  const promiseA = fetch("/api/a");
  const promiseB = fetch("/api/b");

  const [a, b] = await Promise.all([promiseA, promiseB]);

  console.log(a, b);
}

Чем await отличается от then()

Оба подхода работают с промисами, но читаются по-разному.

Через then():

fetch("/api/user")
  .then((response) => response.json())
  .then((user) => {
    console.log(user);
  });

Через await:

async function loadUser() {
  const response = await fetch("/api/user");
  const user = await response.json();

  console.log(user);
}

С await код чаще воспринимается как последовательный сценарий шаг за шагом.

Когда это полезно

await особенно удобен, когда:

  • нужно читать асинхронный код как последовательность шагов
  • важно получить готовое значение из промиса без вложенных then()
  • нужно удобно обрабатывать ошибки через try...catch
  • внутри одной функции есть несколько зависимых асинхронных шагов

Пример:

async function loadProfile() {
  const response = await fetch("/api/profile");
  const profile = await response.json();

  return profile;
}

Такой стиль особенно полезен в коде загрузки данных, работы с API, таймерами и другими асинхронными операциями.

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

Использовать await вне async-функции или модуля

function fn() {
  const value = await Promise.resolve(1);
}

Такой код вызовет синтаксическую ошибку. Внутри обычной функции await использовать нельзя.

Думать, что await блокирует весь JavaScript

async function fn() {
  await new Promise((resolve) => setTimeout(resolve, 1000));
}

fn();
console.log("Этот код всё равно выполнится");

await приостанавливает только текущую асинхронную функцию, а не весь остальной код.

Ожидать ошибку при await обычного значения

async function fn() {
  const value = await 5;
  console.log(value); // 5
}

Обычные значения допустимы, await просто возвращает их.

Запускать независимые операции строго по очереди

async function fn() {
  const user = await fetch("/api/user");
  const settings = await fetch("/api/settings");
}

Если операции друг от друга не зависят, такой код может быть медленнее, чем вариант с Promise.all().

Не обрабатывать ошибку от отклонённого промиса

async function fn() {
  const result = await Promise.reject(new Error("boom"));
  console.log(result);
}

Здесь нужна обработка через try...catch, иначе ошибка уйдёт наружу как отклонение промиса функции.

Быстрая памятка

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

Коротко

await в JavaScript нужен, чтобы дождаться результата промиса и получить уже готовое значение в более прямом и читаемом стиле. Главное, что стоит запомнить: await обычно работает внутри async-функций, умеет ждать и промисы, и обычные значения, не блокирует весь код целиком, а при ошибке выбрасывает исключение, которое обычно ловят через try...catch.