Пошук уроків, статей та іншого контенту
Синтаксис над Promise, що дозволяє писати асинхронний код, який читається як звичайний послідовний код.
Так само, як class виявився синтаксичним цукром над прототипами (модуль «JavaScript під капотом»), async/await — синтаксичний цукор над Promise, а не окремий механізм асинхронності. Під капотом усе одно працюють ті самі Promise, стани й Event Loop із попередніх уроків — async/await лише дозволяє записати той самий ланцюжок так, щоб він виглядав як звичайний послідовний код.
async function greet() {
return "Привіт";
}
greet(); // Promise, що виконається зі значенням "Привіт" — навіть звичайний return загортається автоматично
greet().then((message) => console.log(message)); // "Привіт"await можна використовувати лише всередині async-функції. Він «розгортає» Promise — виконання функції призупиняється саме на цьому рядку, доки Promise не перейде у fulfilled чи rejected, не блокуючи решту програми (Event Loop продовжує обробляти інші завдання):
async function loadUser(userId) {
const user = await fetchUserData(userId); // призупинення тут, доки Promise не виконається
console.log(user); // виконається лише після готовності user
return user;
}// Ланцюжок then (попередній урок)
function loadOrderDetails(userId) {
return getUser(userId)
.then((user) => getOrders(user.id))
.then((orders) => getOrderDetails(orders[0].id));
}
// async/await — та сама логіка, послідовний вигляд
async function loadOrderDetails(userId) {
const user = await getUser(userId);
const orders = await getOrders(user.id);
return await getOrderDetails(orders[0].id);
}Оскільки await «розгортає» Promise у звичайне значення, помилка (reject) перетворюється на звичайний виняток — і обробляється звичним try/catch (модуль «Умовні конструкції» не розглядав try/catch, але механіка та сама, що для будь-якого синхронного винятку):
async function loadUser(userId) {
try {
const user = await fetchUserData(userId);
return user;
} catch (error) {
console.error("Не вдалось завантажити користувача:", error.message);
return null;
}
}Кожен await у прикладі вище чекає на завершення попереднього, перш ніж почати наступний — якщо кроки НЕ залежать один від одного, послідовні await без потреби сповільнюють загальний час виконання. Про паралельне виконання кількох незалежних Promise — наступний урок (Promise.all).
// Повільніше, якщо ordersA і ordersB не залежать одне від одного:
const ordersA = await fetchOrders("A");
const ordersB = await fetchOrders("B"); // чекає завершення попереднього, хоча міг би виконуватись паралельноasync function loadUserProfile(userId) {
try {
const user = await fetchUserData(userId);
const orders = await getOrders(user.id);
return { user, orderCount: orders.length };
} catch (error) {
return { error: error.message };
}
}Спроба використати await поза async-функцією (модулі верхнього рівня — виняток, top-level await там дозволений).
Забутий await перед викликом, що повертає Promise, — код продовжує виконуватись зі самим об'єктом Promise замість очікуваного значення.
Непотрібне послідовне очікування незалежних операцій замість паралельного запуску через Promise.all.
Забутий try/catch навколо await — необроблена помилка «спливає» з async-функції як відхилений Promise, який теж потребує catch там, де функцію викликають.
async оголошує функцію, що завжди повертає Promise; await всередині неї призупиняє виконання до готовності Promise, не блокуючи Event Loop. Це той самий механізм Promise/then із попередніх уроків, лише в синтаксисі, що читається як послідовний код, з try/catch для обробки помилок замість .catch().
Спробуйте самостійно
Перепишіть ланцюжок then із практичного прикладу попереднього уроку (validateEmail → registerUser) через async/await з try/catch.