Ошибки без await
Урок: Ошибки без await
Введение
Когда начинаешь работать с async / await, всё кажется простым: написал await, получил результат, работаешь дальше как с обычными данными.
Но есть важный момент, который часто упускают новички: что будет, если забыть await?
Представь, что ты заказал доставку еды, но вместо того чтобы дождаться курьера, сразу открываешь дверь и ожидаешь, что еда уже там. Очевидно, ничего не произойдёт — ты просто пришёл слишком рано.
В программировании ситуация похожая. Если не дождаться выполнения асинхронной операции, ты начинаешь работать не с результатом, а с «обещанием» этого результата.
Это приводит к ошибкам, которые на первый взгляд выглядят странно и непонятно.
Что происходит без await
Рассмотрим простой пример:
function getData() {
return Promise.resolve('Данные');
}
async function main() {
let result = getData();
console.log(result);
}
main();
Результат:
Promise { "Данные" }
Здесь мы ожидали увидеть "Данные", но получили Promise.
Почему так произошло:
getData()возвращает Promise;- мы не использовали
await; - переменная
resultсодержит Promise, а не значение.
Это одна из самых частых ошибок.
Правильный вариант с await
Добавим await:
function getData() {
return Promise.resolve('Данные');
}
async function main() {
let result = await getData();
console.log(result);
}
main();
Теперь результат:
Данные
Разница в том, что:
await«разворачивает» Promise;- мы получаем реальное значение.
Ошибка при работе с результатом
Посмотрим более опасную ситуацию.
function getUser() {
return Promise.resolve({ name: 'Stepan' });
}
async function main() {
let user = getUser();
console.log(user.name);
}
main();
Результат:
undefined
Почему:
user— это Promise;- у Promise нет свойства
name; - поэтому
user.name—undefined.
Исправим:
function getUser() {
return Promise.resolve({ name: 'Stepan' });
}
async function main() {
let user = await getUser();
console.log(user.name);
}
main();
Теперь всё работает корректно.
Ошибки в цепочке вызовов
Проблема становится ещё серьёзнее, когда операций несколько.
function getUser() {
return Promise.resolve({ name: 'Stepan' });
}
async function main() {
let user = getUser();
let name = user.name.toUpperCase();
console.log(name);
}
main();
Здесь программа упадёт с ошибкой, потому что:
user— это Promise;user.name—undefined;- у
undefinedнельзя вызватьtoUpperCase().
Добавляем await:
function getUser() {
return Promise.resolve({ name: 'Stepan' });
}
async function main() {
let user = await getUser();
let name = user.name.toUpperCase();
console.log(name);
}
main();
Теперь всё работает правильно.
Ошибки с try/catch
Ещё одна важная проблема — обработка ошибок.
function getData() {
return Promise.reject('Ошибка!');
}
async function main() {
try {
let result = getData();
} catch (error) {
console.log(error);
}
console.log('Без await отклонённый Promise не попадает в catch');
}
main();
Здесь ошибка не будет поймана в try/catch.
Почему:
getData()возвращает Promise;- ошибка происходит внутри Promise;
- без
awaitона не попадает вtry/catch.
Исправим:
function getData() {
return Promise.reject('Ошибка!');
}
async function main() {
try {
let result = await getData();
console.log(result);
} catch (error) {
console.log(error);
}
}
main();
Теперь ошибка будет обработана.
Логическая ошибка: код выполняется раньше времени
Иногда ошибка не приводит к падению, но ломает логику.
function getData() {
return Promise.resolve({ value: 42 });
}
async function main() {
let data = getData();
console.log('Данные:', data);
}
main();
Результат:
Данные: Promise { ... }
Мы ожидали увидеть реальные данные, но получили Promise.
Это означает, что код продолжил выполнение раньше, чем данные были готовы.
Когда await не обязателен
Важно понимать: не всегда отсутствие await — ошибка.
Например:
function getData() {
return Promise.resolve('Готово');
}
async function main() {
let promise = getData();
promise.then((data) => {
console.log(data);
});
}
main();
Здесь всё работает, потому что используется then.
Но смешивание then и await может запутать код, поэтому обычно выбирают один подход.
Где это проявляется на практике
Ошибки без await часто встречаются в реальных задачах:
- при работе с API (
fetch); - при загрузке данных;
- при обработке форм;
- при работе с базами данных.
Типичная ошибка — забыть await у fetch и у json():
// Неверно (оба выражения — Promise, не данные):
// let response = fetch('https://api.com/data');
// let data = response.json();
async function correctPattern() {
let response = await Promise.resolve({
json: async () => ({ ok: true }),
});
let data = await response.json();
console.log(data);
}
correctPattern();
Здесь вместо сети показан учебный Promise.resolve с тем же интерфейсом, что у Response: два последовательных await — как в настоящем коде с fetch.
Итоговое понимание
Главная проблема без await в том, что ты работаешь не с результатом, а с Promise.
Это приводит к:
- неправильным данным;
- ошибкам доступа к свойствам;
- неработающему
try/catch; - нарушенной логике программы.
Ключевая идея в том, что await — это не просто синтаксис, а момент, когда ты действительно «дожидаешься» результата.
Если забыть его, код продолжит выполняться, как будто результат уже есть — и именно это становится источником большинства ошибок.