Skip to main content

worker_threads у Node.js

Що таке worker_threads

worker_threads - це вбудований модуль Node.js, який дозволяє запускати JavaScript-код в окремих потоках (workers).

Простіше кажучи: це спосіб виконувати кілька JS-задач паралельно, використовуючи різні CPU-ядра, без блокування основного потоку (event loop).

Навіщо він потрібен

Node.js чудово справляється з асинхронними I/O-операціями (мережевими, файловими, БД). Але якщо код виконує CPU-інтенсивну задачу (наприклад, шифрування, парсинг, обробку зображень) - вона блокує event loop, і сервер перестає відповідати на інші запити.

Рішення: виносити важкі обчислення в окремі потоки за допомогою worker_threads.

1. Як підключити

Модуль вбудований у Node.js (починаючи з версії 10.5, стабільний із 12):

javascript
const { Worker, isMainThread, parentPort } = require('worker_threads');

2. Найпростіший приклад

main.js

javascript
const { Worker } = require('worker_threads'); console.log('Головний потік:', process.pid); const worker = new Worker('./worker.js'); worker.on('message', msg => console.log('Результат від воркера:', msg)); worker.on('exit', () => console.log('Воркер завершив роботу'));

worker.js

javascript
console.log('Воркер запущено:', process.pid); let sum = 0; for (let i = 0; i < 1e9; i++) sum += i; postMessage(sum); // Надсилаємо результат у головний потік

Що відбувається:

  • main.js запускає воркер в окремому потоці.
  • Воркер виконує важку задачу (цикл на мільярд ітерацій).
  • Основний потік не блокується.
  • Коли задача завершена - результат повертається назад через повідомлення.

3. Як працює обмін даними

Між потоками немає спільного контексту (як у багатопроцесних мовах). Вони обмінюються повідомленнями (message passing).

МеханізмПриклад
parentPort.postMessage(data)Воркер надсилає повідомлення в основний потік
worker.on('message', handler)Основний потік слухає відповідь
workerDataМожна передати дані під час створення воркера

Приклад передавання аргументів:

javascript
const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js', { workerData: { iterations: 1e7 } });

worker.js

javascript
const { workerData, parentPort } = require('worker_threads'); let sum = 0; for (let i = 0; i < workerData.iterations; i++) sum += i; parentPort.postMessage(sum);

4. Асинхронна версія (через проміс)

Для зручності можна обгорнути Worker у проміс:

javascript
const { Worker } = require('worker_threads'); function runWorker(path, data) { return new Promise((resolve, reject) => { const worker = new Worker(path, { workerData: data }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', code => { if (code !== 0) reject(new Error(`Worker stopped with code ${code}`)); }); }); } (async () => { const result = await runWorker('./task.js', { n: 1e8 }); console.log('Результат:', result); })();

5. Коли використовувати worker_threads

Підходить дляНе підходить для
CPU-інтенсивних задачЗвичайного I/O (HTTP, файли, БД)
Парсингу й обробки великих данихПростих API-запитів
Шифрування, стисненняАсинхронного введення-виведення
Рендерингу, генерації PDF/зображеньПростої логіки

6. Відмінність від інших способів

ПідхідМодульПроцес чи потікОбмін даними
worker_threadsworker_threadsПотік (спільна пам'ять)Швидкий, через повідомлення
clusterclusterОкремі процеси Node.jsIPC (повільніше)
child_processchild_processОкремий процесЧерез stdout/stdin

worker_threads працює в тому самому процесі, але з окремим потоком JS, тому вони легші й швидші, ніж процеси cluster чи child_process.

7. Додаткові можливості

  • Можна використовувати SharedArrayBuffer для спільної пам'яті.
  • Можна передавати Transferable об'єкти (ArrayBuffer, MessagePort).
  • Підтримуються Atomics для синхронізації даних.
  • Підтримка TypeScript і ES Modules повністю працює.

8. Важливо пам'ятати

  • Потоки-worker не діляться спільним global чи require - у кожного свій контекст.
  • Занадто багато воркерів → великі накладні витрати на пам'ять і комунікацію.
  • Воркер не робить Node.js «багатопоточним» у звичному сенсі - ти сам вирішуєш, коли створювати потоки.

Підсумок

КритерійОпис
ПризначенняПаралельне виконання JS-коду в окремих потоках
Модульworker_threads
Обмін данимиЧерез postMessage / parentPort
ПродуктивністьЛегше й швидше, ніж процеси
Підходить дляCPU-інтенсивних задач (математика, парсинг, шифрування)
З'явивсяУ Node.js 10.5 (стабільний із 12+)

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.