Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «З яких фаз складається Event Loop?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Одна ітерація (tick) Event Loop проходить шість фаз по черзі: **timers → pending callbacks → idle/prepare → poll → check → close callbacks**, а мікрозадачі (`process.nextTick`, `Promise.then`) виконуються між кожною фазою. **Ключове:** `setTimeout(cb, 0)` спрацьовує у фазі timers, а `setImmediate(cb)` - у фазі check, тому їхній порядок відносно один одного не гарантований поза I/O-callback-ом.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Що таке "фаза" Event Loop Event Loop у Node.js реалізовано через бібліотеку **libuv**. Кожна ітерація (цикл) Event Loop ділиться на **фази** - логічні етапи, на яких виконуються різні типи callback-ів. Одна **ітерація** Event Loop називається **tick**. Після виконання всіх фаз цикл починається знову (поки є задачі). ## 2. Основні фази Event Loop | № | Фаза | Що робить | Приклади callback-ів | |---|---|---|---| | 1 | **timers** | Виконує callback-и від `setTimeout()` і `setInterval()` | `setTimeout(cb, 0)` | | 2 | **pending callbacks** | Виконує деякі відкладені системні callback-и (помилки I/O, TCP тощо) | Помилки сокетів, `TCP.onconnection` | | 3 | **idle, prepare** | Внутрішні фази libuv (не використовуються напряму в JS) | - | | 4 | **poll** | Основна фаза очікування I/O. Виконує готові I/O callback-и або чекає нових подій | `fs.readFile()`, мережеві події | | 5 | **check** | Виконує callback-и від `setImmediate()` | `setImmediate(cb)` | | 6 | **close callbacks** | Виконує callback-и закриття ресурсів | `socket.on('close')`, `stream.destroy()` | ## 3. Схематично (в одній ітерації Event Loop): ```javascript ┌───────────────────────────────────────┐ │ 1. timers │ ← setTimeout(), setInterval() ├───────────────────────────────────────┤ │ 2. pending callbacks │ ← системні callback-и (I/O) ├───────────────────────────────────────┤ │ 3. idle, prepare │ ← внутрішні фази libuv ├───────────────────────────────────────┤ │ 4. poll │ ← очікування й обробка I/O подій ├───────────────────────────────────────┤ │ 5. check │ ← setImmediate() ├───────────────────────────────────────┤ │ 6. close callbacks │ ← socket.on('close'), stream.on('close') └───────────────────────────────────────┘ ``` Після цього - нова ітерація (tick). ## 4. Як пов'язані `setTimeout()` і `setImmediate()` Дуже часто питають на співбесідах. | Функція | Де виконується | Коли приблизно | |---|---|---| | `setTimeout(cb, 0)` | **timers** | На початку наступного циклу Event Loop | | `setImmediate(cb)` | **check** | Наприкінці поточного циклу Event Loop | **Приклад:** ```javascript setTimeout(() => console.log('timeout'), 0); setImmediate(() => console.log('immediate')); ``` Результат може бути: ```javascript timeout immediate ``` або ```javascript immediate timeout ``` Усе залежить від того, де було запущено код - до чи після I/O. ## 5. Особлива черга microtasks Крім фаз Event Loop, є **мікрозадачі (microtasks)** - це callback-и від: - `Promise.then()` / `catch()` / `finally()`; - `process.nextTick()`. Вони **не належать жодній фазі**, але виконуються **між фазами** - після кожного виконаного callback-а Event Loop **виконуються всі microtasks**. ### Пріоритет: 1. `process.nextTick()` - виконується **перед** microtasks. 2. Microtasks (`Promise.then`, `queueMicrotask`). 3. Далі - перехід до наступної фази Event Loop. ## 6. Приклад із промисами й nextTick ```javascript setTimeout(() => console.log('timeout'), 0); Promise.resolve().then(() => console.log('promise')); process.nextTick(() => console.log('nextTick')); setImmediate(() => console.log('immediate')); ``` **Результат:** ```javascript nextTick promise timeout immediate ``` Чому: 1. `nextTick` і `promise` → черга microtask; 2. потім фаза `timers` (timeout); 3. потім фаза `check` (immediate). ## 7. Особливості фаз `poll` і `check` ### Фаза **poll**: - Основна фаза Event Loop. - Саме тут Node.js **чекає нових I/O подій**. - Якщо черга порожня: - і є таймери → Event Loop перейде у фазу `timers`; - якщо немає → Event Loop **засне**, чекаючи I/O. ### Фаза **check**: - Виконує callback-и `setImmediate()`. - Якщо `poll` завершився раніше (без подій), керування швидко передається в `check`. ## 8. Фаза `close callbacks` Завершує цикл: - виконує callback-и, пов'язані із закриттям ресурсів (`close`, `destroy`, `disconnect`); - наприклад, після `socket.destroy()` або `process.exit()`. ## 9. Спрощена візуалізація повного циклу ```javascript ┌────────────────────────────────────┐ │ timers (setTimeout, setInterval) │ ├────────────────────────────────────┤ │ pending callbacks (I/O) │ ├────────────────────────────────────┤ │ idle, prepare │ ├────────────────────────────────────┤ │ poll (очікування I/O подій) │ ├────────────────────────────────────┤ │ check (setImmediate) │ ├────────────────────────────────────┤ │ close callbacks (закриття) │ └────────────────────────────────────┘ ▲ │ │ ▼ microtasks (Promises, nextTick) ``` ## 10. Резюме | Фаза | Що робить | Приклади | |---|---|---| | **timers** | Виконує callback-и від `setTimeout` / `setInterval` | `setTimeout(cb, 1000)` | | **pending callbacks** | Системні callback-и від I/O операцій | TCP, DNS | | **idle, prepare** | Внутрішні службові етапи libuv | - | | **poll** | Чекає I/O, обробляє їхні callback-и | `fs.readFile`, `net`, `http` | | **check** | Виконує `setImmediate` | `setImmediate(cb)` | | **close callbacks** | Закриття ресурсів | `socket.on('close')` | | **microtasks** | Міжфазові задачі | `Promise.then()`, `process.nextTick()` |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.