async/await
Синтаксический сахар над промисами. Позволяет писать асинхронный код как синхронный.
Синтаксис
async function loadUser(id) {
const res = await fetch(`/api/users/${id}`);
const user = await res.json();
return user;
}
asyncперед функцией делает её асинхроннойawaitприостанавливает выполнение до разрешения промиса
Async всегда возвращает промис
async function getValue() {
return 42;
}
const result = getValue(); // Promise<42>
Даже если возвращаешь обычное значение — оно оборачивается в промис.
getValue().then((v) => console.log(v)); // 42
Await
Приостанавливает функцию, но не блокирует поток:
async function load() {
console.log('начало');
const data = await fetch('/api/data');
console.log('данные получены');
return data;
}
console.log('до вызова');
load();
console.log('после вызова');
// до вызова
// начало
// после вызова
// данные получены
Пока await ждёт — остальной код продолжает выполняться.
Только внутри async
await нельзя использовать в обычной функции:
function load() {
const data = await fetch('/api'); // SyntaxError
}
Исключение — top-level await в ES-модулях:
// module.js
const data = await fetch('/api/data').then((r) => r.json());
Обработка ошибок
try/catch работает с await:
async function load() {
try {
const res = await fetch('/api/data');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (error) {
console.error('Ошибка:', error.message);
throw error;
} finally {
console.log('завершено');
}
}
Последовательные await
async function process() {
const user = await getUser();
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
return comments;
}
Каждый шаг ждёт предыдущий.
Параллельные
async function process() {
const [user, posts, comments] = await Promise.all([
getUser(),
getPosts(),
getComments(),
]);
return { user, posts, comments };
}
Все три запроса идут одновременно.
Await в цикле
Последовательно:
for (const id of ids) {
const data = await fetchItem(id);
results.push(data);
}
Каждый запрос ждёт предыдущий. Медленно.
Параллельно:
const results = await Promise.all(ids.map((id) => fetchItem(id)));
С ограничением:
const results = await mapLimit(ids, 5, fetchItem);
Await в forEach
Не работает как ожидается:
// Не ждёт
ids.forEach(async (id) => {
const data = await fetchItem(id);
results.push(data);
});
console.log(results); // пусто
forEach не ждёт асинхронные callbacks.
Решение — for...of или Promise.all с map.
Возврат промиса
async function load() {
return fetch('/api');
}
const res = await load(); // Response
await разворачивает промис.
Асинхронные методы класса
class ApiClient {
async get(path) {
const res = await fetch(`${this.baseUrl}${path}`);
return res.json();
}
}
IIFE
(async () => {
const data = await fetchData();
console.log(data);
})();
Итоги
async/await— синтаксис поверх промисов- Функция с
asyncвсегда возвращает промис awaitприостанавливает функцию, не блокирует потокtry/catchдля ошибокPromise.allдля параллельности- Не используй
awaitвforEach