← Назад к вопросам

Приоритет выше у micro или у macro task

2.3 Middle🔥 101 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Приоритет microtask vs macrotask

Microtask имеют БОЛЕЕ ВЫСОКИЙ приоритет чем macrotask. Это критически важно для понимания асинхронного выполнения кода в JavaScript.

Что такое Event Loop

Event Loop — это механизм, который определяет порядок выполнения кода в JavaScript. Он состоит из несколько этапов:

  1. Выполнение синхронного кода (call stack)
  2. Выполнение всех microtask (microtask queue)
  3. Выполнение одной macrotask (macrotask queue)
  4. Повтор с шага 2

Порядок выполнения

Call Stack (синхронный код)
  |
  v
Microtask Queue (ВЫСОКИЙ ПРИОРИТЕТ)
  - Promises (.then, .catch, .finally)
  - async/await
  - MutationObserver
  - queueMicrotask()
  |
  v (только после очистки всех microtask)
Macrotask Queue (НИЗКИЙ ПРИОРИТЕТ)
  - setTimeout
  - setInterval
  - setImmediate
  - requestAnimationFrame
  - I/O операции

Практический пример

console.log("1. Синхронный код");

setTimeout(() => {
  console.log("2. setTimeout (macrotask)");
}, 0);

Promise.resolve()
  .then(() => {
    console.log("3. Promise (microtask)");
  });

console.log("4. Синхронный код");

// Результат:
// 1. Синхронный код
// 4. Синхронный код
// 3. Promise (microtask) — выполнится ПЕРЕД setTimeout!
// 2. setTimeout (macrotask)

Синхронный код выполняется первым (console.log 1 и 4). Затем выполняются все microtask (Promise), и только потом macrotask (setTimeout).

Более сложный пример

console.log("Начало");

// Macrotask
setTimeout(() => {
  console.log("setTimeout 1");
  
  Promise.resolve().then(() => {
    console.log("Promise внутри setTimeout");
  });
}, 0);

// Microtask
Promise.resolve()
  .then(() => {
    console.log("Promise 1");
    
    setTimeout(() => {
      console.log("setTimeout внутри Promise");
    }, 0);
  });

// Еще одна microtask
queueMicrotask(() => {
  console.log("queueMicrotask");
});

console.log("Конец");

// Результат:
// Начало
// Конец
// Promise 1
// queueMicrotask
// setTimeout 1
// Promise внутри setTimeout
// setTimeout внутри Promise

Объяснение:

  1. Выполняются все console.log (синхронный код): "Начало", "Конец"
  2. Затем выполняются все microtask: "Promise 1", "queueMicrotask"
  3. Затем выполняется первая macrotask (первый setTimeout): "setTimeout 1"
  4. После каждой macrotask опять проверяются microtask: "Promise внутри setTimeout"
  5. Затем выполняется вторая macrotask: "setTimeout внутри Promise"

Примеры microtask

// 1. Promise callbacks
Promise.resolve().then(() => console.log("microtask"));

// 2. async/await
async function test() {
  await Promise.resolve();
  console.log("microtask"); // await это просто синтаксический сахар над .then
}

// 3. MutationObserver
const observer = new MutationObserver(() => {
  console.log("microtask");
});
observer.observe(document.body, { childList: true });

// 4. queueMicrotask
queueMicrotask(() => {
  console.log("microtask");
});

Примеры macrotask

// 1. setTimeout / setInterval
setTimeout(() => console.log("macrotask"), 0);

// 2. setImmediate (Node.js только)
setImmediate(() => console.log("macrotask"));

// 3. requestAnimationFrame
requestAnimationFrame(() => console.log("macrotask"));

// 4. I/O операции
fs.readFile("file.txt", () => console.log("macrotask"));

Почему это важно

Случай 1: Race condition с setTimeout

let data = null;

fetch("/api/data")
  .then(response => response.json())
  .then(json => {
    data = json; // Это microtask
  });

setTimeout(() => {
  console.log(data); // Это выполнится ПОСЛЕ того как данные загружены!
}, 0);

Случай 2: Оптимизация перерисовок DOM

// Плохо: requestAnimationFrame нужно для правильной синхронизации с браузером
setTimeout(() => {
  element.style.color = "red";
}, 0);

// Хорошо: используем requestAnimationFrame
requestAnimationFrame(() => {
  element.style.color = "red";
});

Заключение

Приоритет ясен: microtask > macrotask. Все microtask выполняются перед тем, как браузер перейдет к следующей macrotask. Это важно помнить при отладке асинхронного кода и для понимания timing-зависимых проблем.