webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
JavaScript · Урок 14 из 17

Async: Promise и await

Event loop, async/await, параллельный запуск через Promise.all.

Обновлено

Что значит синхронно и асинхронно

Синхронно = каждая строка ждёт, пока закончит предыдущая. Асинхронно = вы запускаете медленную операцию (сетевой запрос, таймер, чтение файла) и продолжаете делать другое; результат придёт позже.

Почему это важно: JS в браузере работает в одном потоке — том же, который рисует страницу и отвечает на клики. Если бы он синхронно ждал запрос 2 секунды, страница зависла бы на 2 секунды.

Event loop — как это работает

  1. Call stack — код, который выполняется прямо сейчас.
  2. Медленные операции передаются браузеру (сеть, таймеры), он выполняет их параллельно.
  3. Когда одна заканчивается, её колбэк попадает в очередь.
  4. Event loop берёт из очереди, только когда стек пуст.

Есть две очереди с разным приоритетом:

Очередь Что попадает Приоритет
microtask .then у Promise, await, queueMicrotask все выполняются до следующей macrotask
macrotask setTimeout, setInterval, события, I/O одна за оборот
console.log(1)
setTimeout(() => console.log(4))          // macrotask
Promise.resolve().then(() => console.log(3)) // microtask
console.log(2)
// 1, 2, 3, 4

Что такое Promise

Promise — объект, который представляет значение, которое ещё придёт, — как чек заказа: еды пока нет, но есть то, чего можно ждать.

У Promise 3 состояния:

Состояние Означает
pending ещё выполняется
fulfilled готово, есть значение
rejected не удалось, есть ошибка

Когда Promise завершился (fulfilled или rejected), состояние больше не меняется.

const wait = ms => new Promise(resolve => setTimeout(resolve, ms))

fetch('/api/user')
  .then(res => res.json())      // выполняется при успехе
  .then(user => render(user))
  .catch(err => showError(err)) // выполняется при ошибке в любом месте цепочки

async / await — то же самое, но как синхронный код

async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`)   // «ставит на паузу» функцию до ответа
    return await res.json()
  } catch (error) {
    return null
  }
}
  • async перед функцией → она всегда возвращает Promise.
  • await → ждёт Promise, не блокируя страницу («стоит» только текущая функция).
  • Ошибки ловятся обычным try/catch.
.then() async/await
Читаемость цепочки, колбэки код сверху вниз
Ошибки .catch() try/catch
Когда короткие цепочки вне async-функций по умолчанию

Последовательно или параллельно — самая частая оптимизация

// ✗ последовательно — второй стартует после первого: 2 × время
const user = await getUser()
const posts = await getPosts()

// ✓ параллельно — оба стартуют сразу
const [user, posts] = await Promise.all([getUser(), getPosts()])

Последовательно — только когда второй запрос зависит от результата первого.

Комбинаторы Promise — виды и когда

Метод Завершается, когда Если один упал Когда
Promise.all все успешны падает сразу нужны все результаты
Promise.allSettled все завершились не падает; получаете статус каждого нужны частичные результаты
Promise.race первый завершился (как угодно) зависит от первого таймаут
Promise.any первый успешный падает, только если упали все несколько источников, подойдёт любой

Классические ошибки

  • forEach с async не ждёт → for...of (последовательно) или Promise.all(arr.map(...)) (параллельно).
  • Забыли await → вместо значения Promise (user.name равно undefined).
  • Promise без catch / try → unhandledrejection.
  • await в цикле, когда запросы независимы, → медленно.

Коротко

  • В JS один поток; медленные операции асинхронны, чтобы страница не зависала.
  • Promise = будущее значение: pending → fulfilled / rejected.
  • async/await + try/catch; Promise.all для параллельной работы.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.