Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чому Node.js вважають однопоточним (single-threaded)?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Node.js однопоточний** у тому сенсі, що весь ваш JavaScript-код виконується в одному основному потоці, де працює event loop. Важкі I/O-операції Node.js делегує пулу фонових потоків бібліотеки libuv, а не блокує ними основний потік. **Ключове:** JS-виконання - однопоточне, але під капотом Node.js багатопоточний завдяки libuv.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що означає «однопоточний» (single-threaded) Коли кажуть, що **Node.js однопоточний**, мають на увазі, що: > Основний потік виконання JavaScript-коду в Node.js - **один**. > Саме в цьому потоці працює **event loop**, який обробляє всі callback-и, промиси та події. Тобто: - У Node.js немає безлічі потоків, як у Java, C++ чи Python (за замовчуванням). - Ваш JS-код виконується **в одному основному потоці**, послідовно. ## Як це працює всередині Node.js побудований на **рушії V8** (виконує JS) та бібліотеці **libuv** (керує асинхронністю й потоками). Схематично: ```javascript ┌───────────────────────────────┐ │ Ваш JavaScript-код (1 потік)│ ← Event Loop └───────────────────────────────┘ ↓ ┌───────────────────┐ │ libuv ThreadPool│ ← фонова робота (I/O) └───────────────────┘ ``` Основна ідея: - JS-код працює в одному потоці. - Коли ви викликаєте асинхронну функцію (наприклад, `fs.readFile`), Node.js **делегує** важку операцію **фоновому пулу потоків (Thread Pool)**, а не блокує основний потік. - Коли операція завершується, її результат повертається назад в **event loop**, і викликається callback або promise. ## Приклад ```javascript const fs = require('fs'); console.log('Початок'); fs.readFile('data.txt', 'utf8', (err, data) => { console.log('Файл прочитано'); }); console.log('Кінець'); ``` **Порядок виводу:** ```javascript Початок Кінець Файл прочитано ``` Чому саме так? - JS виконується в одному потоці. - `fs.readFile` йде у фоновий потік libuv. - Основний потік не чекає і продовжує виконання. ## Але у Node.js є й інші потоки Так, усередині Node.js **є додаткові потоки**, але вони **не виконують JavaScript** напряму. | Компонент | Потоки | Що робить | |---|---|---| | **Event Loop** | 1 | Виконує JS-код, обробляє події | | **libuv Thread Pool** | 4 за замовчуванням | Виконує операції I/O (файли, DNS, крипто) | | **Системні потоки** | багато | ОС, мережеві операції, ядро | Кількість потоків у пулі можна змінити: ```javascript UV_THREADPOOL_SIZE=8 node app.js ``` ## Чому це важливо Node.js **не використовує багатопоточність для виконання JS-коду**, але **використовує додаткові потоки** для фонових операцій. Тож: - Він **однопоточний з точки зору виконання JavaScript**. - Але **багатопоточний під капотом** - для введення-виведення й системних задач. ## Чому це зручно 1. **Проста модель конкурентності** Немає проблем із синхронізацією, м'ютексами та блокуваннями. 2. **Асинхронність замість потоків** Замість безлічі потоків використовується **event loop** і **non-blocking I/O**. 3. **Масштабованість** Завдяки неблокуючій архітектурі Node.js обробляє **тисячі запитів** на одному потоці. ## Але можна використовувати багатопоточність Якщо потрібно розподілити обчислення по ядрах, Node.js пропонує: | Підхід | Модуль | Опис | |---|---|---| | **Cluster API** | `cluster` | Запускає кілька процесів Node.js (за кількістю ядер CPU) | | **Worker Threads** | `worker_threads` | Дозволяє запускати JS-код в окремих потоках | | **child_process** | `fork`, `spawn`, `exec` | Запускає зовнішні процеси | Приклад із **Worker Threads**: ```javascript const { Worker } = require('worker_threads'); new Worker('./worker.js'); // окремий потік для важких обчислень ``` ## Підсумок | Характеристика | Node.js | |---|---| | Потік для JS-коду | Один (event loop) | | Потоки під капотом | Так (у libuv) | | Виконання JS паралельно | Ні | | Асинхронність | Через event loop | | Багатопоточність доступна вручну | Так (через worker_threads, cluster) |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.