В чём вообще проблема
Обычный код выполняется сверху вниз. Асинхронный — нет.
console.log("раз");
setTimeout(() => console.log("два"), 0);
console.log("три");
Выведет: раз, три, два. Даже при нулевой задержке.
Понимание, почему так, — половина всей темы.
Почему так происходит
В браузере одна нить выполнения: она делает всё по очереди и не может ждать. Если бы запрос к серверу останавливал выполнение, страница замирала бы на секунды.
Поэтому долгие операции устроены иначе: вы говорите «сделай это и позови меня, когда закончишь», а выполнение идёт дальше. Когда операция готова, ваш обработчик встаёт в очередь и выполняется, как только освободится нить.
Отсюда правило: всё, что связано с ожиданием, попадает в очередь и выполняется позже, чем идущий следом обычный код.
Первый способ: обработчики
Исторически первый: передаёте функцию, которую вызовут по готовности.
Проблема известна: если операций несколько по цепочке, вложенность растёт, и код превращается в лесенку, которую невозможно читать.
Второй способ: обещания
Обещание — объект, который представляет результат, ещё не полученный. У него три состояния: ожидание, успех, ошибка.
fetch("/api/notes")
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err));
Читается сверху вниз: сделали запрос, потом разобрали ответ, потом использовали, при ошибке в любом месте цепочки попали в обработчик ошибок.
Третий способ: ожидание
Современная запись, за которой всё то же самое:
async function loadNotes() {
try {
const res = await fetch("/api/notes");
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}
}
Здесь код снова выглядит последовательным. Слово ожидания говорит: «остановись тут, пока не будет результата, но не блокируй всё остальное».
Два правила:
- Ожидание работает только внутри функции, помеченной как асинхронная.
- Такая функция всегда возвращает обещание, даже если внутри возвращается обычное значение.
Частые ошибки
Забыли дождаться. Функция вызвана, но результат не дождались — получаете обещание вместо данных.
Ожидание в цикле, когда операции независимы. Пять запросов по очереди вместо одновременных. Если порядок не важен, запускайте их вместе и дожидайтесь всех разом.
Нет обработки ошибок. Упавший запрос без перехвата даёт непонятную ошибку в консоли и оставляет интерфейс в подвешенном состоянии.
Ожидание внутри перебора массива. Классика: обычный перебор не умеет ждать, и код идёт дальше, не дождавшись.
Как проверить, что поняли
Ответьте себе: почему в примере из начала статьи «два» выводится последним, хотя задержка нулевая? Если можете объяснить словами про очередь и освобождение нити — тема закрыта.
Дальше практика: напишите страницу, которая делает три запроса — два независимых одновременно и третий после них, — с обработкой ошибок и состоянием загрузки.
Хватит читать — пора делать
На CohortX можно найти команду под пет-проект и получить тот самый опыт, о котором спрашивают на собеседовании.
Похожие статьи
- TypeScript for beginners: why typesWhich problems types solve, the minimum to get started, and whether to take it on straight after JavaScript.
- TypeScript для новичка: зачем нужны типыКакие проблемы решают типы, минимум для начала работы, и стоит ли браться за это сразу после JavaScript.
- Asynchrony in JavaScript: understanding it once and for allWhy code runs out of order, what a promise is, and how to read the modern syntax without fear.