Что такое async/await и как они связаны с Promise?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Async/Await и их связь с Promise
async/await — это синтаксический сахар над Promise, который делает асинхронный код похожим на синхронный. Это облегчает чтение и отладку кода, работающего с асинхронными операциями.
Promise — основа async/await
Promise — это объект, представляющий состояние асинхронной операции:
// Создание Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
// Использование .then()
promise
.then((result) => console.log(result))
.catch((error) => console.error(error));
Состояния Promise:
- Pending — в процессе
- Fulfilled — выполнено с результатом
- Rejected — отклонено с ошибкой
Async функция — оборачивает результат в Promise
// Обычная функция
function getData() {
return 'hello';
}
console.log(getData()); // 'hello'
// Async функция ВСЕГДА возвращает Promise
async function getDataAsync() {
return 'hello';
}
console.log(getDataAsync()); // Promise { 'hello' }
// Эквивалентно:
function getDataPromise() {
return Promise.resolve('hello');
}
Await — паузирует выполнение до разрешения Promise
// Await можно использовать ТОЛЬКО внутри async функции
async function fetchUser() {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
}
// Это эквивалентно:
function fetchUserWithThen() {
return fetch('https://api.example.com/user')
.then((response) => response.json())
.then((data) => data);
}
// Или еще более явно:
function fetchUserWithThen2() {
return fetch('https://api.example.com/user')
.then((response) => response.json())
.then((data) => Promise.resolve(data));
}
Сравнение: Promise vs Async/Await
1. Простой запрос
С Promise:
function getUser(id) {
return fetch(`/api/users/${id}`)
.then((response) => response.json())
.then((user) => user);
}
getUser(1).then((user) => console.log(user));
С async/await:
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
}
const user = await getUser(1);
console.log(user);
2. Последовательные операции
С Promise (callback hell):
function process() {
return fetch('/api/data')
.then((r) => r.json())
.then((data) => fetch(`/api/details/${data.id}`))
.then((r) => r.json())
.then((details) => fetch(`/api/comments/${details.id}`))
.then((r) => r.json())
.then((comments) => ({
data,
details,
comments,
}));
}
С async/await (читаемо):
async function process() {
const dataResponse = await fetch('/api/data');
const data = await dataResponse.json();
const detailsResponse = await fetch(`/api/details/${data.id}`);
const details = await detailsResponse.json();
const commentsResponse = await fetch(`/api/comments/${details.id}`);
const comments = await commentsResponse.json();
return { data, details, comments };
}
3. Параллельные операции
Неправильно (последовательно):
async function getMultipleUsers() {
const user1 = await fetch('/api/users/1').then(r => r.json()); // Ждёт
const user2 = await fetch('/api/users/2').then(r => r.json()); // Ждёт
// Итого: 2 секунды, если каждый запрос 1 секунда
return { user1, user2 };
}
Правильно (параллельно):
async function getMultipleUsers() {
const [user1, user2] = await Promise.all([
fetch('/api/users/1').then(r => r.json()),
fetch('/api/users/2').then(r => r.json()),
]);
// Итого: 1 секунда (параллельно)
return { user1, user2 };
}
Обработка ошибок
С Promise (.catch):
fetch('/api/data')
.then((r) => r.json())
.then((data) => console.log(data))
.catch((error) => console.error('Error:', error));
С async/await (try/catch):
async function getData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
Важные моменты
1. Async функция ВСЕГДА возвращает Promise
async function test() {
return 42;
}
const result = test();
console.log(result instanceof Promise); // true
console.log(result); // Promise { 42 }
// Чтобы получить значение:
result.then((value) => console.log(value)); // 42
// Или:
const value = await test();
console.log(value); // 42
2. Await можно использовать только в async функции
// Ошибка!
const data = await fetch('/api/data'); // SyntaxError!
// Правильно:
async function main() {
const data = await fetch('/api/data');
}
// Или top-level await (в модулях)
await fetch('/api/data');
3. Ошибка в Promise внутри async
async function test() {
throw new Error('Oops');
}
// Ошибка становится rejection
test()
.catch((e) => console.log(e.message)); // 'Oops'
Promise.all / Promise.race / Promise.allSettled
// Ждёт ВСЕ promises (быстро падает на первую ошибку)
await Promise.all([promise1, promise2, promise3]);
// Ждёт ПЕРВЫЙ результат
await Promise.race([promise1, promise2]);
// Ждёт ВСЕ (не падает на ошибку)
await Promise.allSettled([promise1, promise2]);
Практический пример: API с retry
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`Status ${response.status}`);
return await response.json();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
}
}
}
// Использование
const data = await fetchWithRetry('https://api.example.com/data');
Чеклист
✅ Async/await — это синтаксис для работы с Promise ✅ Async функция всегда возвращает Promise ✅ Await паузирует выполнение до разрешения Promise ✅ Используй try/catch для обработки ошибок ✅ Используй Promise.all для параллельных операций ✅ Await можно использовать только в async функции ✅ Async/await делает код более читаемым, чем .then().then()
Вывод: async/await — это современный способ работать с Promise. Они дают тот же результат, но async/await код выглядит как синхронный и легче читается.