В чем разница между then и async/await?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между then() и async/await
then() и async/await — это два способа работы с промисами в JavaScript. Оба решают проблему асинхронного кода, но имеют принципиальные различия в синтаксисе и подходе.
Основные различия
1. Синтаксис и читаемость
then() - цепочка вызовов (callback style):
function getUserData(userId) {
return fetch(`/api/users/${userId}`)
.then(response => response.json())
.then(user => fetch(`/api/posts/${user.id}`))
.then(response => response.json())
.then(posts => ({ user: posts }))
.catch(error => console.error('Error:', error));
}
async/await - синхронный стиль:
async function getUserData(userId) {
try {
const userResponse = await fetch(`/api/users/${userId}`);
const user = await userResponse.json();
const postsResponse = await fetch(`/api/posts/${user.id}`);
const posts = await postsResponse.json();
return { user, posts };
} catch (error) {
console.error('Error:', error);
}
}
async/await читается как обычный синхронный код, что делает его более понятным для большинства разработчиков.
2. Обработка ошибок
then() - через catch:
fetch('/api/data')
.then(res => res.json())
.then(data => console.log(data))
.catch(error => {
console.error('Ошибка:', error);
// Все ошибки ловятся одним catch
});
async/await - через try/catch:
async function loadData() {
try {
const res = await fetch('/api/data');
const data = await res.json();
console.log(data);
} catch (error) {
console.error('Ошибка:', error);
// Более знаком разработчикам
} finally {
// Опциональный блок для очистки
}
}
3. Параллельное выполнение
then() - через Promise.all:
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => {
const [users, posts, comments] = data;
console.log(users, posts, comments);
});
async/await - более явный:
async function loadAllData() {
const [usersRes, postsRes, commentsRes] = await Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
const [users, posts, comments] = await Promise.all([
usersRes.json(),
postsRes.json(),
commentsRes.json()
]);
console.log(users, posts, comments);
}
4. Контроль потока выполнения
then() - неявный контроль:
fetch('/api/user')
.then(res => res.json())
.then(user => {
// Вторая операция ждет первую
return fetch(`/api/posts/${user.id}`);
})
.then(res => res.json())
.then(posts => processData(posts));
async/await - явный контроль:
async function processUserData() {
const userRes = await fetch('/api/user');
const user = await userRes.json();
// Явно видно, что это ждет результат выше
const postsRes = await fetch(`/api/posts/${user.id}`);
const posts = await postsRes.json();
return processData(posts);
}
Практические рекомендации
Когда выбираю async/await:
- Читаемость кода важнее
- Нужна последовательная логика с зависимостями
- Код содержит условия и циклы в асинхронном потоке
- Работаю с попыткой/ошибкой (try/catch)
async function getUserWithValidation(userId) {
try {
const user = await fetchUser(userId);
if (!user) {
throw new Error('User not found');
}
// Цикл в асинхронном коде - очень удобно
const posts = [];
for (const postId of user.postIds) {
posts.push(await fetchPost(postId));
}
return { user, posts };
} catch (error) {
console.error('Failed to load user:', error);
}
}
Когда выбираю then():
- Работаю с простыми цепочками операций
- Нужно использовать функциональный стиль
- Работаю с методами Promise (Promise.all, Promise.race)
const results = Promise.all(promises)
.then(data => data.filter(item => item.active))
.then(filtered => filtered.map(item => item.name));
Смешивание подходов
// Можно комбинировать async/await с then()
async function mixedApproach() {
const data = await fetch('/api/data')
.then(res => res.json())
.then(json => json.filter(item => item.valid));
return data;
}
Важные различия при работе с ошибками
then() не прерывает цепь:
Promise.reject('Error')
.then(() => 'Step 1') // Пропускается
.then(() => 'Step 2') // Пропускается
.catch(err => 'Caught'); // Ловится здесь
async/await прерывает выполнение:
async function test() {
try {
throw new Error('Error');
console.log('Never reached'); // Не выполнится
} catch (err) {
console.log('Caught'); // Выполнится
}
}
В современной разработке я предпочитаю async/await за его простоту и читаемость, но хорошо знаю both, так как встречаю legacy код с then() и иногда применяю функциональный style с Promise методами.