Workers
The main thread runs a single event loop — perfect for I/O, bad for hashing, parsing, or number-crunching that blocks every request. Worker moves that work to OS threads, each with its own JS runtime and event loop. Max 8 workers per process.
Quick look
Main (main.js) — spawn with data, send a job, print the reply:
Worker (hash-worker.js) — read workerData, listen, reply:
Spawning: new Worker(path, { data }?)
Caution: The option key is
data, notworkerData.new Worker("./w.js", { workerData: … })silently passes nothing — the worker must readglobalThis.workerData, but the parent sends{ data: … }.
Parent-side API:
Messaging both directions
Parent → worker via w.postMessage, worker → parent via global postMessage. Both sides receive via onmessage with the payload on e.data:
Values cross the boundary by structured clone — each message is copied, never shared. Keep messages small and self-contained.
Errors and shutdown
Rules:
- Workers live until
terminate(). There is no idle-exit — the process stays alive while any worker is unterminated. - The process exits once all workers are terminated (and the main loop drains).
- Worker-side uncaught errors surface via the parent's
onerrorand print[worker] unhandled error: …diagnostics. postMessageafterterminate()throws — guard or null out the handle.
Practical example: non-blocking hash endpoint
Keep the HTTP loop free by hashing in a worker pool of one:
The handler returns a Promise, so the connection parks while the worker crunches — other requests keep flowing.
Reference
Troubleshooting
Worker module not found — the path is relative to the spawning script, and needs the extension ("./hasher.js", not "./hasher").
workerData is undefined — parent used the wrong key. Send { data: … }, read globalThis.workerData.
Process won't exit — an unterminated worker is alive. Call w.terminate() for every spawned worker (or process.exit() to force it).
too many workers (max 8) — pool exhausted. Reuse workers across requests instead of spawning per request.
UI still stalls with workers — the job isn't actually offloaded (handler computes inline), or all 8 slots are busy and new spawns throw. Move the loop body into the worker file.
