> Что происходит после выполнения микротасков в JavaScript и как обрабатываются макротаски и синхронный код? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Альфа-банк

Стек: JavaScript

> Пример ответа

Короткий ответ

Сначала выполняется весь синхронный код (стек вызовов). Затем event loop обрабатывает микротаски (Promise, queueMicrotask, MutationObserver) - весь их очередь до опустошения. После этого берётся один макротаск (setTimeout, setInterval, I/O, UI-рендеринг). Между макротасками может произойти рендеринг. Микротаски блокируют макротаски, если добавляются рекурсивно.

Подробное объяснение

Event loop в JavaScript работает по строгому порядку:

  1. Выполняется весь синхронный код в текущем стеке вызовов.
  2. Когда стек пуст, проверяется очередь микротасков. Все микротаски выполняются до полного опустошения очереди (включая новые, добавленные во время обработки).
  3. После очистки микротасков берётся один макротаск из очереди макротасков.
  4. Макротаск выполняется, и цикл повторяется.

Микротаски имеют приоритет над макротасками. Это означает, что если во время обработки микротаска добавляется новый микротаск, он будет выполнен до перехода к следующему макротаску. Такое поведение может привести к бесконечному циклу, если микротаски добавляются рекурсивно.

Макротаски включают: setTimeout, setInterval, setImmediate (Node.js), I/O, события UI, рендеринг. Рендеринг браузера обычно происходит между макротасками, но не гарантируется после каждого.

На практике

  • Используйте микротаски для операций, которые должны выполниться как можно скорее после синхронного кода, но не блокируя UI (например, обновление состояния после асинхронного запроса).
  • Избегайте рекурсивного добавления микротасков - это заблокирует event loop и макротаски (например, таймеры) не будут выполняться.
  • Для отложенных задач, не критичных к времени, используйте макротаски (setTimeout с нулевой задержкой) - они дают браузеру возможность отрендерить изменения.
  • В средах с рендерингом (браузер) учитывайте, что requestAnimationFrame выполняется перед рендерингом, но после микротасков.

Пример кода

JAVASCRIPT
console.log('1: sync');
setTimeout(() => console.log('2: macro'), 0);
Promise.resolve().then(() => {
console.log('3: micro');
Promise.resolve().then(() => console.log('4: micro nested'));
});
console.log('5: sync');
// Вывод: 1, 5, 3, 4, 2

Как отвечать на собеседовании

Начните с краткого определения event loop и его фаз. Укажите приоритет микротасков над макротасками. Приведите пример, демонстрирующий порядок выполнения. Объясните, почему микротаски блокируют макротаски, и упомяните рендеринг как точку между макротасками. Если спросят про Node.js, добавьте различие с браузером (фазы libuv, process.nextTick как микротаск с высшим приоритетом).

Что проверяет интервьюер

  • Понимание event loop как механизма асинхронности.
  • Знание различий между микро- и макротасками.
  • Умение предсказывать порядок выполнения кода.
  • Осознание практических последствий (блокировка, рендеринг).
  • Глубина: способность объяснить, как микротаски влияют на производительность и UI.

Типичные ошибки

  • Путать микротаски с макротасками (например, считать Promise макротаском).
  • Думать, что setTimeout с нулевой задержкой выполняется сразу после синхронного кода.
  • Не учитывать, что микротаски обрабатываются до макротасков, даже если макротаск был запланирован раньше.
  • Забывать про рендеринг между макротасками в браузере.
  • Считать, что event loop - это часть языка, а не среда выполнения (браузер/Node.js).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью