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.