JS Advanced

Микрозадачи (Microtasks)

Разобрать микрозадачи (Promise.then, queueMicrotask) и их приоритет над макрозадачами (setTimeout) в Event Loop.

Продвинутый (Advanced)

Кратко

Microtask — задача с максимальным приоритетом. Все microtasks выполняются ПОСЛЕ текущего синхронного кода, НО ДО следующей макрозадачи. Promise.then, queueMicrotask, MutationObserver — microtasks. setTimeout, setInterval — macrotasks.


Подробно

Очереди задач:

  • Call stack (синхронный код)
  • Microtask queue (Promise.then, queueMicrotask)
  • Macrotask queue (setTimeout, setInterval)

Порядок выполнения: // Задача 1: синхронный код console.log('1');

// Задача 2: microtask Promise.resolve().then(() => console.log('2'));

// Задача 3: microtask queueMicrotask(() => console.log('3'));

// Задача 4: macrotask setTimeout(() => console.log('4'), 0);

console.log('5');

// Вывод: 1, 5, 2, 3, 4

Важно: microtask queue очищается ПОЛНОСТЬЮ

console.log('start');

Promise.resolve().then(() => { console.log('micro1'); Promise.resolve().then(() => console.log('micro2')); });

setTimeout(() => console.log('macro'), 0); console.log('end');

// Вывод: start, end, micro1, micro2, macro // micro2 — тоже microtask, выполняется до macro!

MutationObserver callback — тоже microtask (JA11).

Где это важно:

  • Порядок обновления UI
  • Порядок вызова callback'ов
  • Когда один Promise создаёт другой Promise

Ментальная модель

Microtask queue — как VIP-очередь. Синхронный код — текущий клиент (обслуживается сразу). Microtasks — VIP-клиенты (обслуживаются ВСЕ перед обычными). Macrotasks — обычные клиенты (обслуживаются по одному после VIP).


Примеры

**Самый простой:**

javascript
console.log('1');

Promise.resolve().then(() => console.log('2'));

setTimeout(() => console.log('3'), 0);

console.log('4');

// Вывод: 1, 4, 2, 3
// Синхронный → Microtask → Macrotask

Базовый порядок: sync → microtask → macrotask.

**Простой:**

javascript
Promise.resolve()
  .then(() => {
    console.log('micro1');
    return Promise.resolve();
  })
  .then(() => console.log('micro2'));

Promise.resolve()
  .then(() => console.log('micro3'));

setTimeout(() => console.log('macro'), 0);

// Вывод: micro1, micro3, micro2, macro
// micro3 выполняется ДО micro2,
// потому что micro1 уже завершился

Порядок microtasks зависит от порядка разрешения Promises.

**Реальный пример:**

javascript
// Опасный паттерн: рекурсивные microtasks
function flood() {
  Promise.resolve().then(flood);
}
flood(); // Microtask queue никогда не опустеет!
// setTimeout НЕ выполняется
// UI зависает

// Безопасный вариант
function safe() {
  setTimeout(() => {
    // Нагрузка распределяется по macrotasks
    // UI остаётся отзывчивым
    safe();
  }, 0);
}

Рекурсивные microtasks блокируют macrotasks и UI.


Частые ошибки

**Неправильно:** Думать, что microtasks и macrotasks выполняются параллельно

**Почему:** Они выполняются последовательно: сначала ВСЕ microtasks, потом одна macrotask.

**Правильно:** Microtask queue опустеет полностью → одна macrotask → снова microtasks.

**Неправильно:** Путать queueMicrotask и setTimeout(fn, 0)

**Почему:** queueMicrotask — microtask (приоритет). setTimeout — macrotask (после microtasks).

**Правильно:** queueMicrotask = VIP. setTimeout = обычный.


Важно запомнить

  • Microtasks: Promise.then, queueMicrotask, MutationObserver
  • Macrotasks: setTimeout, setInterval, I/O
  • Microtask queue опустеет полностью перед следующей macrotask
  • Рекурсивные microtasks блокируют macrotasks
  • Порядок: sync → microtasks → macrotask

Связь

Назад: Вы знаете async/await (JA5) и Event Loop (DA11). Микрозадачи — внутренний механизм, стоящий за колбэками Promise.

Вперёд: Следующий урок (JV12) — конструктор и new — как создаются объекты.

Материалы курса JS Advanced — PROlab Academy.