Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Event loop у Node.js». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Event loop** - це нескінченний цикл, який бере готові callback-и з черг (таймери, I/O, промиси) і виконує їх фазами, поки в програмі є хоча б одна задача. **Ключове:** саме event loop дозволяє одному потоку V8 обслуговувати тисячі одночасних з'єднань, не блокуючись на введенні-виведенні.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Що таке Event Loop простими словами **Event Loop** - це нескінченний цикл, який: 1. бере задачі з черг (наприклад, callback-и від `fs`, `setTimeout`, `http`, `Promise` тощо), 2. виконує їх у певному порядку (по фазах), 3. продовжує крутитися, поки є хоча б одна задача. Ідея: замість безлічі потоків - один потік (JS-рушій V8), який швидко перемикається між задачами, не блокуючись на введенні-виведенні. ## 2. Компоненти, що беруть участь в Event Loop | Компонент | Роль | |---|---| | **V8** | Виконує сам JavaScript-код | | **libuv** | Реалізує Event Loop, Thread Pool та асинхронний I/O | | **Queue (черги)** | Зберігають callback-и й задачі, які потрібно виконати | | **OS Kernel** | Виконує операції введення-виведення, повідомляє libuv про готовність | ## 3. Принцип роботи Event Loop Спрощено: 1. Node.js виконує синхронний код (наприклад, тіло файлу `app.js`); 2. Коли зустрічається асинхронна операція (`fs.readFile`, `setTimeout`, `fetch`, `net` тощо) - вона передається в **libuv**; 3. libuv виконує її у фоні (або делегує ОС); 4. Коли операція завершена - результат ставиться в **чергу подій**; 5. **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`). ### Порядок: 1. Виконується поточна макрозадача (наприклад, із `timers`); 2. Після неї - *усі мікрозадачі* (`Promise.then`, `process.nextTick`); 3. Далі - перехід до наступної фази Event Loop. `process.nextTick()` виконується навіть **раніше**, ніж `Promise.then()` - у спеціальній "внутрішній" черзі. ## 6. Приклад покрокового виконання ```javascript setTimeout(() => console.log('timeout'), 0); setImmediate(() => console.log('immediate')); Promise.resolve().then(() => console.log('promise')); process.nextTick(() => console.log('nextTick')); console.log('sync'); ``` **Результат:** ```javascript sync nextTick promise timeout immediate ``` **Чому саме так:** 1. `sync` - виконується одразу; 2. `nextTick` → виконується до переходу до наступної фази; 3. `promise` → мікрозадача, виконується після `nextTick`; 4. `timeout` → фаза timers; 5. `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. Візуалізація (текстова) ```javascript ┌──────────────────────────────┐ │ JS виконується в V8 │ │ (синхронний код, проміси) │ └──────────────┬───────────────┘ ▼ ┌──────────────────────────────┐ │ libuv │ │ - Event Loop │ │ - Thread Pool │ └──────────────┬───────────────┘ ▼ ┌──────────────────────────────┐ │ Операційна система │ │ (I/O, файли, мережа, таймери) │ └──────────────────────────────┘ ``` ## 10. Підсумок | Компонент | Що робить | |---|---| | **Event Loop** | Керує порядком виконання задач | | **libuv** | Реалізує цикл подій і фонові операції | | **V8** | Виконує сам JS-код і callback-и | | **Thread Pool** | Виконує важкі операції поза основним потоком | | **Queue (черги)** | Зберігають callback-и й microtasks/macrotasks |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.