Асинхронность. Промисы и async/await
Free PreviewКогда мы пишем обычный код, он выполняется строка за строкой — синхронно. Но что если нужно загрузить данные с сервера или подождать ответа пользователя? Такие операции занимают неизвестное время, и если просто «подождать» — браузер зависнет и перестанет реагировать.
Для решения этой задачи в JavaScript существует асинхронность.
Однопоточность JavaScript
JavaScript — однопоточный язык. Это означает, что он может выполнять только одну операцию в один момент времени. Пока выполняется одна задача, все остальные ждут.
Браузер решает эту проблему с помощью цикла событий (event loop): медленные операции (запросы к серверу, таймеры, ввод пользователя) отдаются в отдельную очередь, а основной поток продолжает работу. Когда операция завершается, её результат возвращается обратно.
Детально механика event loop — тема для отдельного глубокого изучения. Отличное объяснение с визуализацией можно найти в видео «What the heck is the event loop anyway?» (на английском).
Колбэки — первый подход
Исторически первым решением были колбэки — функции, которые передаются как аргументы и вызываются, когда операция завершилась. Мы уже встречали их: setTimeout, forEach, обработчики событий — всё это колбэки.
setTimeout(() => { console.log('Прошла секунда'); }, 1000); console.log('Это выполнится сразу'); // 'Это выполнится сразу' // 'Прошла секунда' — через секундуjs
Проблема возникает, когда операции нужно выполнять последовательно. Код превращается в так называемый callback hell — глубокую вложенность колбэков, которую сложно читать и поддерживать:
loadUser(id, (user) => { loadProfile(user, (profile) => { loadPosts(profile, (posts) => { // ещё глубже... }); }); });js
Promise — обещание
Promise (обещание) — это объект, представляющий результат асинхронной операции, который станет известен в будущем. Promise может находиться в одном из трёх состояний:
pending— ожидает выполнения;fulfilled— выполнен успешно;rejected— завершился с ошибкой.
Цепочка .then() / .catch() позволяет обработать результат:
fetch('https://api.example.com/cities') .then((response) => response.json()) .then((data) => { console.log(data); }) .catch((error) => { console.log('Ошибка:', error); });js
Каждый .then() получает результат предыдущего и может вернуть новое значение или новый Promise. Это позволяет выстраивать читаемые цепочки вместо вложенных колбэков.
async / await — современный синтаксис
async/await — это надстройка над Promise, которая позволяет писать асинхронный код так, будто он синхронный:
async function loadCities() { try { const response = await fetch('https://api.example.com/cities'); const data = await response.json(); console.log(data); } catch (error) { console.log('Ошибка:', error); } } loadCities();js
Ключевое слово async перед функцией означает, что она всегда возвращает Promise. Ключевое слово await внутри такой функции «приостанавливает» выполнение и ждёт, пока Promise выполнится — при этом браузер не зависает, остальные задачи продолжают работать.
Блок try/catch здесь заменяет .catch() и ловит ошибки, как в синхронном коде.
fetch — запросы к серверу
fetch — это встроенная в браузер функция для отправки HTTP-запросов. Она возвращает Promise:
async function getUser(id) { const response = await fetch(`https://api.example.com/users/${id}`); if (!response.ok) { throw new Error(`Ошибка: ${response.status}`); } const user = await response.json(); return user; }js
fetch — основной инструмент для работы с серверными данными в браузере. Он поддерживает все типы запросов (GET, POST, PUT, DELETE) и настройку заголовков. Подробнее можно почитать на doka.guide.
Итого
Асинхронность — важная и обширная тема, которую невозможно полностью охватить в рамках обзорного урока. Главное, что нужно запомнить:
- JavaScript однопоточный, но умеет работать с медленными операциями не блокируя браузер;
- Колбэки — первый подход, но при вложенности становятся нечитаемыми;
- Promise — удобнее, цепочки
.then()/.catch(); async/await— самый современный и читаемый способ работы с асинхронным кодом;fetch— стандартный инструмент для HTTP-запросов.
Для более глубокого изучения темы рекомендую статью об асинхронности на doka.guide и раздел про Promise на MDN.
Это завершающий урок третьего модуля. В следующем модуле мы применим всё изученное на практике — научимся работать с DOM-деревом и добавлять интерактивность на нашу страницу.