Встречается на 59% собеседований по JavaScript

Что такое Event Loop

Event Loop — это механизм в JavaScript, который позволяет выполнять асинхронный код в однопоточной модели, управляя очередями задач и обеспечивая их выполнение, когда основной поток освобождается. Он следит за порядком выполнения синхронного кода, микрозадач и макрозадач, что критично для понимания асинхронности в браузере и Node.js.

Как это работает

JavaScript выполняется в одном потоке, поэтому для обработки асинхронных операций (таймеры, запросы, события) используется Event Loop. Его работа состоит из нескольких этапов:

  1. Синхронный код: все вызовы попадают в Call Stack и выполняются последовательно.
  2. Асинхронные операции: когда встречается асинхронная функция (например, setTimeout или fetch), она передается в Web APIs (в браузере) или в libuv (в Node.js), а колбэк регистрируется для последующего выполнения.
  3. Очистка стека: когда Call Stack пуст, Event Loop обрабатывает очереди задач.
  4. Повторение цикла: процесс продолжается, пока есть задачи.

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

Event Loop использует две основные очереди:

  • Микрозадачи (Microtasks): сюда попадают колбэки промисов (.then(), .catch(), .finally()), queueMicrotask, а также MutationObserver. Микрозадачи имеют приоритет и выполняются сразу после завершения текущего синхронного кода, но перед макрозадачами.
  • Макрозадачи (Macrotasks): включают setTimeout, setInterval, setImmediate, события (например, onclick), а также I/O-операции. Они выполняются после того, как все микрозадачи обработаны.

Пример

Рассмотрим порядок выполнения в следующем коде:

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

setTimeout(() => {
  console.log('Макрозадача');
}, 0);

Promise.resolve().then(() => {
  console.log('Микрозадача');
});

console.log('Конец синхронного кода');

Вывод будет:

text
Синхронный код
Конец синхронного кода
Микрозадача
Макрозадача

Объяснение: сначала выполняется весь синхронный код, затем Event Loop обрабатывает очередь микрозадач (промис), и только потом — макрозадачу (setTimeout).

Подводные камни

  • Блокировка потока: если в микрозадаче запустить бесконечный цикл, Event Loop не перейдет к макрозадачам, и страница зависнет.
  • Порядок таймеров: setTimeout с задержкой 0 не гарантирует мгновенное выполнение — он ждет, пока стек освободится и все микрозадачи завершатся.
  • Различия окружений: в Node.js есть process.nextTick, который выполняется до микрозадач, а setImmediate — после макрозадач, что может отличаться от браузерного поведения.

Когда использовать

Понимание Event Loop необходимо для:

  • Оптимизации производительности: избегание блокировки основного потока тяжелыми вычислениями.
  • Работы с асинхронными API: правильное использование промисов, async/await и таймеров.
  • Отладки неочевидного порядка выполнения кода.

Коротко

  • Event Loop — это цикл, который управляет выполнением синхронного кода, микрозадач и макрозадач в одном потоке.
  • Микрозадачи (промисы, queueMicrotask) выполняются раньше макрозадач (setTimeout, события).
  • Call Stack должен быть пуст, прежде чем Event Loop начнет обрабатывать очереди.
  • Знание порядка выполнения помогает избегать ошибок и писать эффективный асинхронный код.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы