Concurrency
Fairyfly gives you three layers. Picking the wrong one is the usual cause of a server that "gets stuck".
There is no single "4-thread pool" doing everything. Each subsystem owns its threads:
JavaScript itself never runs in parallel with other JavaScript. Two JS sections execute one after the other, always.
Decision table
Example: parallel fan-out
All three requests are in flight at once — each fetch slot has its own
thread, so a fan-out like this costs one loop, not three.
Top-level
awaitworks in files (modules). It does not work inff -e '...', which is evaluated as a script — wrap it in an async IIFE there, or put the code in a file.
Example: non-blocking file I/O in a handler
Sync calls block the loop thread — fine for a CLI, wrong inside a server:
Example: CPU-bound work → Worker
Workers have their own JS runtime and event loop. They share no state
and talk only by messages (structured clone). The worker scope has
console, timers, postMessage, workerData, and performance — no
fs, no fetch, no http.serve.
Limits worth memorising
Gotchas
Promise.allfails fast — one rejection rejects the whole batch. UsePromise.allSettledwhen every result matters.- Sync
fs, a longwhileloop, or a big synchronous parse delays every pending timer and connection. - Workers never exit on their own; the process waits for
terminate(). - Worker files are classic scripts —
import/exportinside a worker throws.
See also
- Event loop
- Workers · API: Worker
- API: fs — sync vs
*Async - Limitations
