async/await и обработка ошибок
async/await — это красивый синтаксис поверх промисов. С ним асинхронный код выглядит как синхронный: пишешь сверху вниз, читаешь как обычную историю. Это то, как пишут 99% современного JavaScript-кода.
🔷 async — функция всегда возвращает Promise
Ключевое слово async перед функцией делает её асинхронной. Главное последствие: такая функция всегда возвращает Promise, даже если внутри нет ничего асинхронного. Если функция вернёт обычное значение — оно автоматически обернётся в успешный промис.
// Обычная async-функция
async function greet() {
return 'Привет!'; // автоматически → Promise.resolve('Привет!')
}
// Вызываем как обычно — но результат это промис
greet().then(msg => console.log(msg)); // 'Привет!'
// Стрелочная async-функция
const getData = async () => {
return { users: [] };
};
// Проверим:
console.log(getData() instanceof Promise); // true!
⏸️ await — ждём промис
await можно использовать только внутри async-функции. Он «приостанавливает» выполнение функции до тех пор, пока промис не выполнится, и возвращает его результат. Остальной код продолжает работать — функция просто ждёт в фоне.
// Вспомогательная функция — имитирует задержку
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function loadData() {
console.log('Начинаем загрузку...');
await delay(2000); // ждём 2 секунды
console.log('Данные загружены!');
return { name: 'Иван', age: 25 };
}
loadData().then(data => console.log(data));
// Начинаем загрузку...
// (через 2 сек) Данные загружены!
// { name: 'Иван', age: 25 }
💡 Магия await: код после await выглядит синхронным, но на самом деле асинхронный. Функция ставится на паузу, браузер обрабатывает другие события, а когда промис выполнится — функция продолжается с того места.
🛡️ Обработка ошибок: try/catch
В async/await обработка ошибок выглядит как в обычном синхронном коде — через try/catch. Если промис отклоняется — ошибка «бросается» и попадает в блок catch.
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ошибка: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Не удалось загрузить пользователя:', error.message);
return null; // возвращаем null при ошибке
} finally {
console.log('Запрос завершён');
// скрываем лоадер и т.д.
}
}
// Использование
const user = await fetchUser(42);
if (user) {
console.log(user.name);
}
⚠️ Не забывай про try/catch! Необработанная ошибка в async-функции создаёт «unhandled promise rejection» — предупреждение в консоли и потенциально сломанное состояние приложения.
🚀 Параллельное выполнение через Promise.all
Если написать несколько await подряд — они выполнятся последовательно. Но иногда нужно запустить несколько запросов одновременно и дождаться всех. Для этого используют Promise.all вместе с await:
// ❌ Плохо: 3 секунды (1+1+1)
async function sequential() {
const users = await fetchUsers(); // 1 сек
const products = await fetchProducts(); // + 1 сек
const orders = await fetchOrders(); // + 1 сек
return { users, products, orders };
}
// ✅ Хорошо: ~1 секунда (параллельно)
async function parallel() {
const [users, products, orders] = await Promise.all([
fetchUsers(),
fetchProducts(),
fetchOrders()
]);
return { users, products, orders };
}
📊 async/await vs .then() — что выбрать?
fetch('/api/data')
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(err => {
console.error(err);
});
async function loadData() {
try {
const res = await fetch('/api/data');
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}
}
Оба варианта делают одно и то же. async/await — предпочтителен для большинства случаев: код читается линейно, легче добавить промежуточные операции, удобнее дебажить. .then() удобен для коротких цепочек и потоков данных.
✅ Итоги урока
asyncперед функцией — она всегда возвращает Promiseawait— ждёт промис, используется только внутри async-функции- try/catch/finally — стандартная обработка ошибок в async/await
- Несколько await подряд — последовательное выполнение
await Promise.all([...])— параллельное выполнение нескольких промисов- async/await — это синтаксический сахар над промисами, не замена им
- Предпочитай async/await за читаемость; .then() удобен для коротких цепочек
В следующем уроке разберём JSON — универсальный формат обмена данными между фронтом и бэкендом. 🚀
async/await и обработка ошибок
7 вопросов