Await: примеры (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 в циклах — последовательная обработка элементов массива:
async function processArray(array) {
for (const item of array) {
const result = await complexAsyncOperation(item);
console.log(result);
}
}Параллельная обработка с ограничением количества одновременных операций:
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» для повторных попыток:
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:
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]);
}