Async и await

async/await — это синтаксический сахар над промисами, который позволяет писать асинхронный код так, будто он синхронный. Он делает код проще для чтения и отладки, сохраняя при этом все преимущества промисов.

Основной синтаксис

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

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data; // эквивалентно resolve(data)
}

Вызов этой функции:

fetchData().then(data => console.log(data));

Или внутри другой async-функции:

async function handleData() {
  const data = await fetchData();
  console.log(data);
}

Как работает await

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

async function example() {
  console.log('Начало');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('Прошла секунда');
}

Вывод:

Начало
(через 1 секунду) Прошла секунда

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

Ошибки в async/await обрабатываются с помощью стандартного try/catch:

async function safeFetch() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('Сервер вернул ошибку');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Не удалось загрузить данные:', error.message);
    throw error; // можно пробросить дальше, если нужно
  }
}

Это гораздо удобнее, чем .catch() в цепочках промисов, особенно при сложной логике.

Важные ограничения

  • await можно использовать только внутри функций, объявленных как async
  • Нельзя использовать await на верхнем уровне модуля (вне функции), если только не используется top-level await (поддержка зависит от окружения; в React Native — не рекомендуется)
  • async-функция всегда возвращает промис, даже если в ней нет await

Пример: последовательная и параллельная загрузка

Последовательно (медленно):

async function loadSequentially() {
  const user = await fetchUser();
  const posts = await fetchPosts(user.id);
  return { user, posts };
}

Параллельно (быстро):

async function loadInParallel() {
  const userPromise = fetchUser();
  const postsPromise = fetchPosts(); // предположим, что ID не нужен сразу
  const user = await userPromise;
  const posts = await postsPromise;
  return { user, posts };
}

Или с Promise.all:

async function loadWithAll() {
  const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
  return { user, posts };
}

Рекомендация

Используйте async/await в большинстве случаев — он проще, читаемее и лучше сочетается с обычными конструкциями языка (if, for, try/catch). Избегайте смешивания .then() и await в одном блоке кода без веской причины.