> Каков порядок выполнения синхронных задач, микротасков и макротасков в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: amoCRM, IT-One, Библио-Глобус
Стек: JavaScript
> Пример ответа
Короткий ответ
В JavaScript порядок выполнения определяется event loop: сначала выполняется весь синхронный код (текущий call stack), затем - все микротаски (Promise.then, queueMicrotask, MutationObserver), и только после полного опустошения очереди микротасков - один макротаск (setTimeout, setInterval, I/O, рендеринг). После каждого макротаска цикл повторяется: снова все микротаски, затем следующий макротаск. Микротаски всегда имеют приоритет над макротасками.
Подробное объяснение
Event loop работает по строгому алгоритму:
- Синхронный код - выполняется полностью, пока call stack не опустеет. Это включает весь текущий скрипт и вызовы функций.
- Микротаски - после каждого синхронного блока и после каждого макротаска. Очередь микротасков обрабатывается до полного опустошения. Если во время обработки микротаска добавляет новый микротаск, он тоже выполнится в этой же итерации.
- Макротаски - берётся только один макротаск из очереди за итерацию. После его выполнения снова обрабатываются все микротаски.
Ключевое отличие: микротаски - это "быстрые" продолжения, которые должны выполниться до следующего рендеринга или I/O. Макротаски - это отложенные задачи, которые могут ждать.
Важно: рендеринг браузера происходит между макротасками, но не между микротасками. Поэтому если в микротаске запустить бесконечный цикл, страница зависнет - рендеринг не случится.
На практике
Для senior-позиции важно не просто назвать порядок, а объяснить последствия:
- Промисы создают микротаски, поэтому их then-цепочки выполняются до следующего макротаска. Это значит, что несколько Promise.resolve().then() подряд выполнятся "батчем", без вставки между ними других задач.
- setTimeout(fn, 0) не гарантирует выполнение через 0 мс - он попадёт в очередь макротасков и выполнится после всех текущих микротасков.
- async/await - это синтаксический сахар над промисами: await создаёт микротаск для продолжения функции.
- requestAnimationFrame - это отдельный тип задач, выполняемый перед рендерингом, но после микротасков. Его нельзя путать с макротасками.
- Для тяжёлых вычислений лучше использовать Web Workers или разбивать на части через setTimeout, чтобы дать браузеру возможность отрендерить.
Пример кода
JAVASCRIPTconsole.log('1: sync');setTimeout(() => {console.log('4: macro');Promise.resolve().then(() => console.log('5: micro inside macro'));}, 0);Promise.resolve().then(() => console.log('2: micro')).then(() => console.log('3: micro chain'));// Вывод:// 1: sync// 2: micro// 3: micro chain// 4: macro// 5: micro inside macro
Объяснение: сначала синхронный код, затем все микротаски (включая цепочку), затем один макротаск, и после него - его микротаск.
Как отвечать на собеседовании
Начните с чёткого порядка: синхронный код → микротаски → макротаск → микротаски → макротаск. Затем добавьте детали: почему микротаски приоритетнее, что происходит с рендерингом, как ведут себя async/await. Приведите пример с выводом в консоль и объясните его. Если спросят про Node.js - упомяните, что там нет рендеринга, но порядок тот же, плюс есть process.nextTick, который выполняется до остальных микротасков.
Что проверяет интервьюер
Интервьюер проверяет:
- понимание event loop как механизма, а не заученного порядка;
- способность предсказать порядок вывода в сложных примерах с вложенными промисами и таймерами;
- знание отличий между браузером и Node.js;
- понимание влияния микротасков на производительность и рендеринг;
- умение объяснить, почему нельзя блокировать микротаски.
Типичные ошибки
- Утверждение, что setTimeout(0) выполнится сразу после синхронного кода - на самом деле после всех микротасков.
- Забывают, что микротаски, добавленные внутри микротаска, выполняются в той же итерации.
- Путают requestAnimationFrame с макротасками - это отдельный тип.
- Не учитывают process.nextTick в Node.js - он выполняется до Promise.then.
- Считают, что макротаски выполняются "по одному за раз" в строгом порядке FIFO - на самом деле порядок зависит от типа таймера и задержки, но в рамках одной задержки - FIFO.
- Не упоминают рендеринг - для фронтенда это критично.
> Похожие задачи по frontend
Как работает функция groupBy в JavaScript
Как собрать неопределённое количество аргументов функции в JavaScript и работать с ними
Что должен возвращать колбэк в методе sort в JavaScript
Почему async функция возвращает Promise
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью