Что такое async/await в JavaScript
Есть ошибка, которую легко не заметить даже в рабочем приложении.
Код выглядит нормально. Линтер ничего не показывает. Тесты проходят. Но страница почему-то открывается дольше, чем должна.
Часто причина оказывается в том, как именно разработчик использует async/await.
Когда человек впервые видит await, обычно возникает простая мысль: программа остановилась и ждёт ответа сервера.
Логика понятная. В коде написано:
const user = await getUser();Значит, кажется, что JavaScript теперь ничего больше не делает.
Но это не так.
await приостанавливает только текущую функцию. Остальная часть приложения продолжает работать: браузер обрабатывает события, пользователь может взаимодействовать со страницей, выполняются другие задачи.
Именно здесь чаще всего возникает первое неправильное понимание асинхронности.
Почему вообще появился async/await
JavaScript изначально не был языком, где все операции выполняются строго последовательно.
В браузере постоянно есть задачи, которые нельзя выполнить мгновенно:
запросить данные с сервера;
загрузить файл;
получить информацию из базы данных;
дождаться ответа внешнего сервиса.
Если бы программа каждый раз полностью останавливалась на таких операциях, любой сайт зависал бы при обычной загрузке данных.
Поэтому в JavaScript появилась асинхронная модель.
Сначала были callback-функции. Потом разработчики получили Promise. А затем появился async/await, который сделал работу с ними удобнее.
Под капотом всё ещё Promise
Здесь часто возникает путаница.
Многие воспринимают async/await как новый механизм выполнения кода. На самом деле это только другой способ записывать работу с Promise.
Например:
fetch('/api/user')
.then(response => response.json())
.then(user => {
console.log(user);
});Можно записать так:
async function loadUser() {
const response = await fetch('/api/user');
const user = await response.json();
console.log(user);
}Внутри происходит примерно одно и то же.
Разница в том, что второй вариант проще читать, особенно когда появляется несколько операций подряд.
Главная проблема - не await, а лишнее ожидание
Сам по себе await редко становится причиной проблем.
Проблемы появляются, когда им случайно заставляют программу ждать там, где это не нужно.
Например:
const user = await getUser();
const posts = await getPosts();
const settings = await getSettings();На первый взгляд всё выглядит нормально.
Но если данные независимы, приложение делает лишнюю работу:
сначала ждёт пользователя, потом начинает получать посты, потом только запрашивает настройки.
Хотя все три операции могли стартовать одновременно.
В таком случае лучше:
const [user, posts, settings] = await Promise.all([
getUser(),
getPosts(),
getSettings()
]);Такие ошибки часто появляются в личных кабинетах, аналитических панелях и больших интерфейсах.
Например, одна страница может одновременно загружать профиль пользователя, список уведомлений и статистику.
Каждый запрос отдельно работает быстро, но из-за последовательных await пользователь ждёт дольше.
## Небольшой нюанс, который часто забывают
Есть интересный момент с Promise.
Он начинает выполняться не тогда, когда появляется await, а в момент создания.
Сравним:
const usersPromise = getUsers();
const postsPromise = getPosts();
const users = await usersPromise;
const posts = await postsPromise;Оба запроса уже запущены.
А здесь второй запрос начнётся только после первого:
const users = await getUsers();
const posts = await getPosts();В маленьком примере разницы почти нет.
Но в приложении, которое собирает данные из нескольких сервисов, такие детали начинают влиять на скорость загрузки.
await не делает программу быстрее
Есть распространённая ошибка мышления: будто переход на async/await автоматически ускоряет код.
Нет.
async/await не про скорость. Он про удобство работы с асинхронным кодом.
Быстродействие зависит от того, какие операции выполняются последовательно, а какие можно запускать параллельно.
Иногда более короткий и красивый код оказывается медленнее.
Ещё один момент про Node.js
Есть нюанс, который особенно важен для серверной разработки.
await не блокирует event loop Node.js.
Но это не значит, что любой код внутри приложения выполняется без задержек.
Например, тяжёлые вычисления с большими объёмами данных всё равно могут занять основной поток и повлиять на скорость ответа сервера.
Асинхронность помогает ждать внешние операции. Она не превращает обычные вычисления в мгновенные.
## Где async/await используется сегодня
Сейчас без него сложно представить обычный JavaScript-проект.
Он используется:
при работе с API;
во фронтенд-приложениях;
в Node.js;
при запросах к базам данных;
при обработке файлов.
Но важен не сам факт использования await.
Гораздо важнее понимать, где программа действительно должна ждать результат.
Когда await лучше не добавлять
Иногда await появляется просто по привычке.
Например:
await saveLog();
return result;Если сохранение лога никак не влияет на дальнейшую работу, возможно, ждать его завершения не нужно.
Каждый await добавляет точку ожидания.
Перед ним полезно задать простой вопрос:
нужно ли мне получить результат прямо сейчас или эту операцию можно выполнить отдельно?
Главное про async/await
async/await не сделал JavaScript другим языком.
Он просто изменил способ записи асинхронного кода.
Под удобным синтаксисом всё ещё работают Promise и обычная система выполнения JavaScript.
Поэтому проблема обычно не в самом await.
Проблема появляется тогда, когда программа ждёт то, чего ждать вообще не требовалось.
Комментарии
Чтобы оставить комментарий, войдите в аккаунт.