Event loop у Node.js
1. Що таке Event Loop простими словами
Event Loop - це нескінченний цикл, який:
- бере задачі з черг (наприклад, callback-и від
fs,setTimeout,http,Promiseтощо), - виконує їх у певному порядку (по фазах),
- продовжує крутитися, поки є хоча б одна задача.
Ідея: замість безлічі потоків - один потік (JS-рушій V8), який швидко перемикається між задачами, не блокуючись на введенні-виведенні.
2. Компоненти, що беруть участь в Event Loop
| Компонент | Роль |
|---|---|
| V8 | Виконує сам JavaScript-код |
| libuv | Реалізує Event Loop, Thread Pool та асинхронний I/O |
| Queue (черги) | Зберігають callback-и й задачі, які потрібно виконати |
| OS Kernel | Виконує операції введення-виведення, повідомляє libuv про готовність |
3. Принцип роботи Event Loop
Спрощено:
- Node.js виконує синхронний код (наприклад, тіло файлу
app.js); - Коли зустрічається асинхронна операція (
fs.readFile,setTimeout,fetch,netтощо) - вона передається в libuv; - libuv виконує її у фоні (або делегує ОС);
- Коли операція завершена - результат ставиться в чергу подій;
- Event Loop бере готові callback-и з черги й виконує їх у V8.
4. Фази Event Loop
Кожна ітерація Event Loop називається tick. Одна ітерація проходить через кілька фаз (спрощено):
| Фаза | Що робить | Приклади |
|---|---|---|
| 1. timers | Виконує callback-и від setTimeout() і setInterval() | setTimeout(cb, 0) |
| 2. pending callbacks | Обробляє callback-и деяких системних операцій | Помилки TCP, сокети |
| 3. idle, prepare | Внутрішні фази libuv (рідко використовуються напряму) | - |
| 4. poll | Чекає нових I/O подій і виконує їхні callback-и | fs.readFile(), мережеві запити |
| 5. check | Виконує callback-и від setImmediate() | setImmediate(cb) |
| 6. close callbacks | Закриває ресурси | socket.on('close') |
Після цього цикл повторюється, поки є задачі.
5. Окремі черги (microtasks і macrotasks)
Node.js, як і браузер, має дві черги задач:
- macrotasks - звичайні задачі (
setTimeout,setImmediate, I/O callbacks); - microtasks - мікрозадачі (
Promise.then,process.nextTick).
Порядок:
- Виконується поточна макрозадача (наприклад, із
timers); - Після неї - усі мікрозадачі (
Promise.then,process.nextTick); - Далі - перехід до наступної фази Event Loop.
process.nextTick() виконується навіть раніше, ніж Promise.then() - у спеціальній "внутрішній" черзі.
6. Приклад покрокового виконання
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));
console.log('sync');Результат:
sync
nextTick
promise
timeout
immediateЧому саме так:
sync- виконується одразу;nextTick→ виконується до переходу до наступної фази;promise→ мікрозадача, виконується післяnextTick;timeout→ фаза timers;immediate→ фаза check.
7. Чому Event Loop робить Node.js швидким
- Node.js не блокується під час I/O (читання файлів, запитів у мережу);
- усі асинхронні операції виконуються у фоні;
- поки вони виконуються, Event Loop продовжує обробляти інші задачі.
Це дозволяє Node.js обслуговувати тисячі одночасних з'єднань в одному потоці.
8. Коли Event Loop "завмирає"
Якщо виконати важку синхронну операцію (наприклад, while(true) або for на мільйони ітерацій),
то Event Loop "заблокується" - ні таймери, ні callback-и не зможуть виконатися.
Рішення: виносити важкі задачі у Worker Threads, child_process або нативні аддони.
9. Візуалізація (текстова)
┌──────────────────────────────┐
│ JS виконується в V8 │
│ (синхронний код, проміси) │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ libuv │
│ - Event Loop │
│ - Thread Pool │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ Операційна система │
│ (I/O, файли, мережа, таймери) │
└──────────────────────────────┘10. Підсумок
| Компонент | Що робить |
|---|---|
| Event Loop | Керує порядком виконання задач |
| libuv | Реалізує цикл подій і фонові операції |
| V8 | Виконує сам JS-код і callback-и |
| Thread Pool | Виконує важкі операції поза основним потоком |
| Queue (черги) | Зберігають callback-и й microtasks/macrotasks |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.