> Какие микротаски кроме Promise существуют в JavaScript? (JavaScript)

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

Компании: VK

Стек: JavaScript

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

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

Микротаски в JavaScript - это очередь задач, которые выполняются после завершения текущего синхронного кода и до начала следующей макротаски. Основной источник микротасок - Promise (.then, .catch, .finally), но также к ним относятся queueMicrotask(), MutationObserver, а в некоторых средах - process.nextTick (Node.js) и await (который синтаксически оборачивает Promise). Важно отличать их от макротасок: setTimeout, setInterval, setImmediate, requestAnimationFrame, события DOM.

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

Микротаски - это отдельная очередь в event loop, которая обрабатывается полностью перед переходом к следующей макротаске. Если во время выполнения микротаски добавляются новые микротаски, они будут выполнены в той же итерации event loop, что может привести к бесконечному циклу.

Основные источники микротасок:

  1. Promise - самый распространённый источник. Каждый вызов .then(), .catch(), .finally() ставит callback в очередь микротасок.
  2. queueMicrotask() - явный API для добавления функции в очередь микротасок. Доступен в браузерах и Node.js (с версии 11).
  3. MutationObserver - наблюдает за изменениями DOM и вызывает callback после завершения текущей задачи, но до рендеринга. Технически это микротаска.
  4. await - оператор, который внутри себя использует Promise, поэтому после await продолжение функции попадает в очередь микротасок.
  5. process.nextTick() - специфичен для Node.js. Формально это не микротаска, а отдельная очередь с ещё более высоким приоритетом, но на практике её часто рассматривают вместе с микротасками.

Важно: setTimeout, setInterval, setImmediate, requestAnimationFrame - это макротаски, они выполняются после полной очистки очереди микротасок.

На практике

Понимание микротасок критично для:

  • Порядка выполнения асинхронного кода - если вы смешиваете Promise и setTimeout, порядок будет неочевиден без знания приоритетов.
  • Оптимизации производительности - queueMicrotask позволяет выполнить работу сразу после текущей задачи, не дожидаясь следующей макротаски.
  • Отладки гонок - микротаски могут выполняться между рендерингом и обработкой событий, что влияет на визуальное обновление.
  • Работы с MutationObserver - например, для батчинга изменений DOM.

На практике в браузере порядок такой: синхронный код → микротаски (все, включая добавленные в процессе) → рендеринг → макротаска → микротаски → ...

Пример кода

JAVASCRIPT
console.log('1: sync');
Promise.resolve().then(() => console.log('2: promise'));
queueMicrotask(() => console.log('3: queueMicrotask'));
setTimeout(() => console.log('4: setTimeout'), 0);
// Вывод:
// 1: sync
// 2: promise
// 3: queueMicrotask
// 4: setTimeout

Пример с MutationObserver:

JAVASCRIPT
const observer = new MutationObserver(() => console.log('mutation'));
const div = document.createElement('div');
document.body.appendChild(div);
observer.observe(document.body, { childList: true });
div.setAttribute('data-test', '1');
console.log('sync');
// Вывод: sync, затем mutation (микротаска)

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

Начните с определения микротасок и их места в event loop. Назовите основные источники: Promise, queueMicrotask, MutationObserver, await. Упомяните process.nextTick как специфичный для Node.js, но уточните, что это отдельная очередь с более высоким приоритетом. Приведите пример порядка выполнения с setTimeout. Если спросят про await - объясните, что это синтаксический сахар над Promise, поэтому он тоже создаёт микротаску.

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

  • Понимание event loop и очередей задач.
  • Умение различать микротаски и макротаски.
  • Знание неочевидных источников микротасок, кроме Promise.
  • Понимание приоритетов выполнения в разных средах (браузер vs Node.js).
  • Способность объяснить практические последствия (например, почему setTimeout(0) не гарантирует выполнение после Promise).

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

  • Утверждение, что setTimeout(0) выполняется сразу после синхронного кода - на самом деле после всех микротасок.
  • Игнорирование MutationObserver как источника микротасок.
  • Путаница между process.nextTick и микротасками - это разные очереди.
  • Забывание, что await тоже создаёт микротаску, и порядок после await не гарантирован относительно других микротасок.
  • Утверждение, что микротаски выполняются перед рендерингом - это верно, но рендеринг может происходить и между микротасками в некоторых браузерах (хотя обычно нет).

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

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