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

Какие знаешь очереди в Event Loop?

1.7 Middle🔥 261 комментариев
#JavaScript Core

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

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

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

Какие знаешь очереди в Event Loop

Event Loop - это механизм, который управляет выполнением кода в JavaScript. В нём используется несколько типов очередей для разных операций.

Основная структура Event Loop

Event Loop имеет три основные очереди:

// 1. Call Stack (стек вызовов) - синхронный код
// 2. Microtask Queue (очередь микротасок)
// 3. Macrotask Queue (очередь макротасок)

// Порядок выполнения:
// 1. Выполняются синхронный код (Call Stack)
// 2. Все микротаски (Microtask Queue)
// 3. Одна макротаска (Macrotask Queue)
// 4. Повторяется

Microtask Queue (Очередь микротасок)

Микротаски имеют БОЛЕЕ ВЫСОКИЙ приоритет и выполняются ЕЩЁ ДО перейти к макротаскам:

console.log('1. Синхронный код');  // Выведет 1

Promise.resolve().then(() => {
  console.log('3. Микротаска (Promise)');  // Выведет 3
});

setTimeout(() => {
  console.log('5. Макротаска (setTimeout)');  // Выведет 5
}, 0);

console.log('2. Ещё синхронный код');  // Выведет 2

// Порядок вывода: 1, 2, 3, 5

Что входит в Microtask Queue:

  • Promises (.then(), .catch(), .finally())
  • queueMicrotask() - прямой доступ к очереди
  • MutationObserver
  • process.nextTick() в Node.js (имеет ещё более высокий приоритет)
// Примеры микротасок
Promise.resolve().then(() => console.log('Promise'));

queueMicrotask(() => console.log('queueMicrotask'));

const observer = new MutationObserver(() => {
  console.log('MutationObserver');
});
observer.observe(document.body, { childList: true });
document.body.innerHTML = '<div></div>'; // Триггер

Macrotask Queue (Очередь макротасок)

Макротаски имеют БОЛЕЕ НИЗКИЙ приоритет. После каждой макротаски выполняются ВСЕ микротаски:

console.log('Start');  // 1

setTimeout(() => {
  console.log('Макротаска 1');  // 3
  Promise.resolve().then(() => {
    console.log('Микротаска после макро 1');  // 4
  });
}, 0);

setTimeout(() => {
  console.log('Макротаска 2');  // 6
}, 0);

Promise.resolve().then(() => {
  console.log('Микротаска');  // 2
});

console.log('End');  // 1

// Порядок: Start, End, Микротаска, Макротаска 1, Микротаска после макро 1, Макротаска 2

Что входит в Macrotask Queue:

  • setTimeout()
  • setInterval()
  • setImmediate() (Node.js)
  • requestAnimationFrame() - немного особенный (выполняется перед render)
  • I/O операции
  • UI события (click, scroll и т.д.)

Полный цикл Event Loop

console.log('Синхронный 1');  // 1

setTimeout(() => {
  console.log('Макротаска');
  Promise.resolve().then(() => console.log('Микротаска в макротаске'));
}, 0);

Promise.resolve()
  .then(() => {
    console.log('Микротаска 1');
    queueMicrotask(() => console.log('Вложенная микротаска'));
  })
  .then(() => console.log('Микротаска 2'));

console.log('Синхронный 2');  // 2

// Вывод:
// 1. Синхронный 1
// 2. Синхронный 2
// 3. Микротаска 1
// 4. Вложенная микротаска
// 5. Микротаска 2
// 6. Макротаска
// 7. Микротаска в макротаске

requestAnimationFrame() - особый случай

rAF выполняется в особой позиции - между макротаской и рендерингом:

console.log('Start');

requestAnimationFrame(() => {
  console.log('rAF'); // Выполнится перед render
});

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

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

console.log('End');

// Порядок
// Start, End, Promise, setTimeout, rAF (перед render)

Практический пример: оптимизация

// BAD - синхронное обновление DOM в цикле (blocking)
for (let i = 0; i < 1000; i++) {
  document.body.innerHTML += `<div>${i}</div>`;
}

// GOOD - используем microtasks
const fragments = [];
for (let i = 0; i < 1000; i++) {
  fragments.push(`<div>${i}</div>`);
}
Promise.resolve().then(() => {
  document.body.innerHTML = fragments.join('');
});

// BETTER - используем requestAnimationFrame для синхронизации с refresh rate браузера
requestAnimationFrame(() => {
  const fragment = document.createDocumentFragment();
  for (let i = 0; i < 1000; i++) {
    const div = document.createElement('div');
    div.textContent = i;
    fragment.appendChild(div);
  }
  document.body.appendChild(fragment);
});

Визуальная схема приоритетов

Высокий приоритет:
1. Call Stack (синхронный код)
2. process.nextTick() (только Node.js)
3. Microtask Queue (Promise, queueMicrotask, MutationObserver)
4. requestAnimationFrame()
5. Render (перерисовка страницы)
6. Macrotask Queue (setTimeout, setInterval, I/O)

Низкий приоритет

Практический совет

// Если нужна низкая задержка - используй Microtask
Promise.resolve().then(() => {
  updateUI();
});

// Если нужна синхронизация с render - используй rAF
requestAnimationFrame(() => {
  animateElement();
});

// Если задача не срочная - используй Macrotask
setTimeout(() => {
  trackAnalytics();
}, 0);

Понимание Event Loop критично для написания высокопроизводительного кода и избежания блокировок UI.

Какие знаешь очереди в Event Loop? | PrepBro