Await: примеры (JAVASCRIPT)

Оператор await для работы с Promise в JavaScript
Раздел: Асинхронность, Ключевые слова
await(expression: Promise): value (resolved from Promise)

Основные сведения о операторе await

Оператор await приостанавливает выполнение асинхронной функции до разрешения переданного Promise. Это ключевая часть синтаксиса async/await, который упрощает работу с асинхронным кодом.

Использование оператора возможно только внутри функций, объявленных с ключевым словом async. Основная цель — ожидание результата Promise без блокировки основного потока выполнения.

Оператор принимает единственный аргумент — выражение, которое возвращает Promise. Если передаётся значение, не являющееся Promise, оно преобразуется в разрешённый Promise. Возвращает оператор значение, с которым был разрешён Promise. Если Promise отклонён, генерируется исключение.

Базовые примеры применения

Ожидание результата Promise, возвращающего строку:

async function fetchMessage() {
  const message = await new Promise(resolve => {
    setTimeout(() => resolve('Привет, мир!'), 1000);
  });
  console.log(message);
}

fetchMessage();
// Через 1 секунду в консоли:
// Привет, мир!

Использование с функцией fetch для получения данных:

async function getUserData(userId) {
  const response = await fetch(`/api/users/${userId}`);
  const data = await response.json();
  return data;
}
// Возвращает объект с данными пользователя

Похожие подходы в JavaScript

Цепочки методов then() и catch() — классический способ работы с Promise. Они обеспечивают явную обработку успешного результата и ошибок, но могут создавать сложные вложенные структуры.

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

Оператор yield в генераторах может управлять асинхронным выполнением при использовании с библиотеками, но требует дополнительной обвязки. Для асинхронного кода предпочтительнее использовать async/await из-за читаемости и простоты обработки ошибок.

Аналоги в других языках программирования

В Python используется синтаксис async/await с модулем asyncio:

import asyncio

async def fetch_data():
    await asyncio.sleep(1)
    return 'Данные'

async def main():
    result = await fetch_data()
    print(result)

asyncio.run(main())
Данные

В PHP оператор await применяется в контексте корутин и требует декларации асинхронной функции через ключевое слово async:

<?
async function fetchUser($id) {
    return await fetchUserData($id);
}
?>

В C# оператор await используется в методах, помеченных модификатором async, и требует возвращаемого типа Task или Task.

public async Task GetContentAsync() {
    return await httpClient.GetStringAsync(url);
}

Распространённые ошибки

Использование await вне async-функции приводит к синтаксической ошибке:

function test() {
  const result = await Promise.resolve(5);
}
// SyntaxError: await is only valid in async function

Отсутствие обработки отклонённых Promise может привести к необработанным исключениям:

async function riskyOperation() {
  const data = await fetch('invalid-url');
  // При ошибке сети выполнение прервется
}

// Правильный подход:
async function safeOperation() {
  try {
    const data = await fetch('invalid-url');
  } catch (error) {
    console.error('Ошибка:', error);
  }
}

Последовательное выполнение независимых операций замедляет работу:

async function slow() {
  const a = await fetchDataA(); // Ожидание
  const b = await fetchDataB(); // Ожидание только после A
  return {a, b};
}

// Быстрее:
async function fast() {
  const [a, b] = await Promise.all([
    fetchDataA(),
    fetchDataB()
  ]);
  return {a, b};
}

Эволюция оператора

В стандарте ES2022 была добавлена возможность использования await на верхнем уровне в модулях. Это позволяет применять оператор вне функций при условии, что код выполняется как модуль.

// В модуле JavaScript
const data = await fetch('/api/data').then(r => r.json());
console.log(data);

Также обсуждается предложение «Decorators for async functions», которое может предоставить дополнительные возможности метапрограммирования для асинхронных функций, но оно ещё не вошло в стандарт.

Расширенные сценарии применения

Итерация с await в циклах — последовательная обработка элементов массива:

Пример javascript
async function processArray(array) {
  for (const item of array) {
    const result = await complexAsyncOperation(item);
    console.log(result);
  }
}

Параллельная обработка с ограничением количества одновременных операций:

Пример javascript
async function limitedParallel(tasks, limit) {
  const results = [];
  for (let i = 0; i < tasks.length; i += limit) {
    const chunk = tasks.slice(i, i + limit);
    const chunkResults = await Promise.all(
      chunk.map(task => task())
    );
    results.push(...chunkResults);
  }
  return results;
}

Использование с паттерном «Retry» для повторных попыток:

Пример javascript
async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url);
      return await response.json();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(res => setTimeout(res, 1000 * (i + 1)));
    }
  }
}

Ожидание нескольких событий с использованием Promise.race:

Пример javascript
async function fetchWithTimeout(url, timeout = 5000) {
  const fetchPromise = fetch(url);
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Таймаут')), timeout);
  });
  
  return await Promise.race([fetchPromise, timeoutPromise]);
}

JS await function comments

En
Await Pauses the execution of an async function and waits for the resolution of a Promise.