> Что происходит после выполнения микротасков в JavaScript и как обрабатываются макротаски и синхронный код? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Альфа-банк
Стек: JavaScript
> Пример ответа
Короткий ответ
Сначала выполняется весь синхронный код (стек вызовов). Затем event loop обрабатывает микротаски (Promise, queueMicrotask, MutationObserver) - весь их очередь до опустошения. После этого берётся один макротаск (setTimeout, setInterval, I/O, UI-рендеринг). Между макротасками может произойти рендеринг. Микротаски блокируют макротаски, если добавляются рекурсивно.
Подробное объяснение
Event loop в JavaScript работает по строгому порядку:
- Выполняется весь синхронный код в текущем стеке вызовов.
- Когда стек пуст, проверяется очередь микротасков. Все микротаски выполняются до полного опустошения очереди (включая новые, добавленные во время обработки).
- После очистки микротасков берётся один макротаск из очереди макротасков.
- Макротаск выполняется, и цикл повторяется.
Микротаски имеют приоритет над макротасками. Это означает, что если во время обработки микротаска добавляется новый микротаск, он будет выполнен до перехода к следующему макротаску. Такое поведение может привести к бесконечному циклу, если микротаски добавляются рекурсивно.
Макротаски включают: setTimeout, setInterval, setImmediate (Node.js), I/O, события UI, рендеринг. Рендеринг браузера обычно происходит между макротасками, но не гарантируется после каждого.
На практике
- Используйте микротаски для операций, которые должны выполниться как можно скорее после синхронного кода, но не блокируя UI (например, обновление состояния после асинхронного запроса).
- Избегайте рекурсивного добавления микротасков - это заблокирует event loop и макротаски (например, таймеры) не будут выполняться.
- Для отложенных задач, не критичных к времени, используйте макротаски (setTimeout с нулевой задержкой) - они дают браузеру возможность отрендерить изменения.
- В средах с рендерингом (браузер) учитывайте, что requestAnimationFrame выполняется перед рендерингом, но после микротасков.
Пример кода
JAVASCRIPTconsole.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).
> Похожие задачи по frontend
Можно ли выполнять более приоритетные промисы кроме setTimeout и что это дает пользователю
Почему ошибку в промисе лучше обрабатывать через catch, а не через console.error?
Как модифицировать и отображать данные во frontend?
Как улучшить сигнатуру функции, чтобы избежать передачи undefined?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью