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

За что отвечает Event Loop кроме micro и macro tasks

1.3 Junior🔥 111 комментариев
#Браузер и сетевые технологии

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

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

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

Event Loop: полные обязанности кроме микро и макро задач

Event Loop - это намного больше чем просто управление очередями задач. Он отвечает за координацию всего асинхронного выполнения кода в JavaScript, и его обязанности гораздо шире, чем микротаски и макротаски.

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

Event Loop постоянно выполняет следующий цикл:

while (eventLoop.waitForTask()) {
  // 1. Выполнить одну макротаску
  const macrotask = macrotaskQueue.pop();
  if (macrotask) execute(macrotask);
  
  // 2. Выполнить все микротаски
  while (microtaskQueue.hasTasks()) {
    const microtask = microtaskQueue.pop();
    execute(microtask);
  }
  
  // 3. Проверить нужна ли перерисовка
  if (isRepaintTime()) {
    applyStyles();
    layout();
    paint();
  }
  
  // 4. Выполнить requestAnimationFrame callbacks
  executeAnimationFrameCallbacks();
  
  // 5. Обработать другие события
  handleUserInteractions();
  handleIntersectionObservers();
  handleResizeObservers();
  // и многое другое...
}

1. Управление Call Stack (стеком вызовов)

Event Loop управляет самым главным - стеком вызовов:

function a() {
  console.log('a');
  b();
}

function b() {
  console.log('b');
  c();
}

function c() {
  console.log('c');
}

a();
// Event Loop управляет этим стеком: a() -> b() -> c() -> pop -> pop -> pop

Event Loop отвечает за:

  • Выполнение функций из Call Stack
  • Выполнение глобального контекста
  • Синхронный код (который идёт первым)

2. Управление Callback Queue (очередь callback'ов)

Это разные очереди для разных типов callback'ов:

// Макротаски (Macrotask Queue):
- setTimeout
- setInterval
- setImmediate (Node.js)
- I/O operations
- UI events
- requestIdleCallback

// Микротаски (Microtask Queue):
- Promise.then/catch/finally
- MutationObserver
- process.nextTick (Node.js)
- queueMicrotask()
- Object.observe (deprecated)

// Другие очереди:
- requestAnimationFrame (rAF Queue)
- Render Queue

Пример различных очередей:

console.log('1 - синхронно');

setTimeout(() => console.log('2 - макротаска'), 0);

Promise.resolve().then(() => console.log('3 - микротаска'));

requestAnimationFrame(() => console.log('4 - animation frame'));

queueMicrotask(() => console.log('5 - микротаска'));

console.log('6 - синхронно');

// Порядок выполнения:
// 1 - синхронно
// 6 - синхронно
// 3 - микротаска
// 5 - микротаска
// 4 - animation frame
// 2 - макротаска

3. Управление Rendering (перерисовка страницы)

Event Loop определяет КОГДА браузер перерисует страницу:

// Инициирует перерисовку
const element = document.querySelector('.box');
element.style.width = '100px'; // Изменение DOM

// Синхронно ещё виден старый размер
console.log(element.offsetWidth); // может быть 50px

// Event Loop решает перерисовать
// Браузер:
// 1. Выполняет все микротаски
// 2. Вычисляет style changes
// 3. Layout (reflow)
// 4. Paint (repaint)
// 5. Composite

Пример оптимизации рендеринга через Event Loop знание:

// ПЛОХО - вызывает много reflows
for (let i = 0; i < 1000; i++) {
  element.style.width = (i * 10) + 'px';
  console.log(element.offsetWidth); // Заставляет браузер пересчитывать layout
}

// ХОРОШО - батчим изменения
for (let i = 0; i < 1000; i++) {
  element.style.width = (i * 10) + 'px';
}
// Event Loop сам решит когда перерисовать

// ОТЛИЧНОЕ - использование requestAnimationFrame
requestAnimationFrame(() => {
  element.style.width = '100px';
  // Гарантирует выполнение ПЕРЕД следующей перерисовкой
});

4. requestAnimationFrame (rAF)

Это специальная очередь, которая выполняется БЕ перед perеприсовкой, не в основной очереди:

console.log('1');

setTimeout(() => console.log('2 - макротаска'), 0);

requestAnimationFrame(() => console.log('3 - перед перерисовкой'));

Promise.resolve().then(() => console.log('4 - микротаска'));

console.log('5');

// Выполнение:
// 1
// 5
// 4 - микротаска
// 3 - requestAnimationFrame (перед перерисовкой)
// 2 - макротаска

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

function animateElement(element, duration = 1000) {
  const startTime = performance.now();
  
  function animate(currentTime) {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);
    
    element.style.opacity = progress;
    element.style.transform = `translateX(${progress * 100}px)`;
    
    if (progress < 1) {
      requestAnimationFrame(animate);
    }
  }
  
  requestAnimationFrame(animate);
  // Event Loop гарантирует, что animate вызовется прямо перед перерисовкой
}

5. MutationObserver

Event Loop отвечает за когда вызывать MutationObserver callbacks:

const observer = new MutationObserver((mutations) => {
  console.log('Mutations detected:', mutations);
});

observer.observe(document.body, {
  attributes: true,
  childList: true,
  subtree: true
});

// Event Loop вызовет MutationObserver callback после всех микротасок
// но ПЕРЕД следующей макротаской

document.body.appendChild(document.createElement('div'));
Promise.resolve().then(() => console.log('После микротаски, но MutationObserver уже вызвался'));

6. IntersectionObserver

Отвечает за отслеживание видимости элементов в viewport:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Element is visible');
      // Event Loop вызывает это после перерисовки
    }
  });
});

observer.observe(element);
// Event Loop проверяет видимость и вызывает callback
// обычно после requestAnimationFrame и перед следующей макротаской

7. ResizeObserver

Отслеживает изменения размера элементов:

const resizeObserver = new ResizeObserver((entries) => {
  entries.forEach(entry => {
    console.log('Element resized:', entry.contentRect);
    // Event Loop вызывает callback когда размер изменился
  });
});

resizeObserver.observe(element);

// Event Loop сам определит когда это нужно вызвать

8. Обработка User Interactions (события)

Event Loop управляет когда обрабатываются события:

button.addEventListener('click', () => {
  console.log('Click handler');
  // Event Loop помещает это в очередь событий
});

// Порядок обработки события:
// 1. User clicks button
// 2. Event Loop берёт событие
// 3. Выполняет все listeners (синхронно)
// 4. Выполняет все микротаски
// 5. Может перерисовать
// 6. Переходит к следующему событию

9. Управление Memory (сборка мусора)

Event Loop взаимодействует с garbage collector:

// Event Loop определяет когда можно запустить сборку мусора
// Обычно это происходит когда:
// - Нет текущих задач
// - Нет очередей callback'ов
// - Браузер имеет "свободное время"

const largeObject = { /* ... */ };
// После удаления ссылки
// Event Loop и GC решат когда освободить память

10. Обработка Web Workers

Event Loop координирует communication с Web Workers:

const worker = new Worker('worker.js');

worker.postMessage({ data: 'test' });

worker.onmessage = (event) => {
  console.log('Message from worker:', event.data);
  // Event Loop вызывает это когда пришло сообщение
};

// Event Loop:
// - Отправляет сообщение в Worker thread
// - Слушает ответ
// - Вызывает callback в основном потоке

11. Network Request Handling

Event Loop отвечает за completion callbacks fetch/XHR:

fetch('/api/data')
  .then(response => {
    console.log('Response received');
    // Event Loop вызовет это когда пришёл ответ
    // Это микротаска
  })
  .catch(error => {
    // Event Loop вызовет это при ошибке
    // Также микротаска
  });

// Event Loop:
// - Инициирует сетевой запрос
// - Слушает завершение
// - Помещает callback в микротаски

12. IndexedDB и Storage API

Event Loop управляет callback'ами для асинхронных операций с БД:

const request = indexedDB.open('myDatabase');

request.onsuccess = (event) => {
  // Event Loop вызывает это когда БД открыта
};

request.onerror = (event) => {
  // Event Loop вызывает это при ошибке
};

Полная диаграмма Event Loop

┌─────────────────────────────────────────────────────────┐
│                    Event Loop Cycle                      │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  1. Выполнить одну макротаску (setTimeout, setInterval) │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  2. Выполнить ВСЕ микротаски (Promise, queueMicrotask) │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  3. Вычислить стили и выполнить layout (reflow)         │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  4. Выполнить requestAnimationFrame callbacks          │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  5. Перерисовать страницу (paint + composite)          │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  6. Обработать User Events (click, scroll, etc.)       │
└─────────────────────────────────────────────────────────┘
            ↓
┌─────────────────────────────────────────────────────────┐
│  7. Проверить Observers (Intersection, Resize, etc.)   │
└─────────────────────────────────────────────────────────┘
            ↓
         (повторять)

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

За что отвечает Event Loop кроме micro и macro tasks | PrepBro