Runnable, self-contained examples live in the
examples/ folder
of the repository. Each one installs with npm install threadsx and runs with
plain node — no bundler required — using the modern worker form
new Worker(new URL("./worker.mjs", import.meta.url)).
Offload a CPU-bound route in an HTTP server
Run heavy work in a long-lived worker so the server’s event loop stays responsive. (full example)
primes.worker.mjs
import { expose } from "threadsx/worker"
function countPrimesUpTo(limit) {
let count = 0
for (let n = 2; n <= limit; n++) {
let isPrime = true
for (let d = 2; d * d <= n; d++) {
if (n % d === 0) { isPrime = false; break }
}
if (isPrime) count++
}
return count
}
expose(countPrimesUpTo)
server.mjs
import { createServer } from "node:http"
import { spawn, Thread, Worker } from "threadsx"
const countPrimes = await spawn(
new Worker(new URL("./primes.worker.mjs", import.meta.url))
)
const server = createServer(async (req, res) => {
const url = new URL(req.url, "http://localhost")
if (url.pathname === "/primes") {
const count = await countPrimes(Number(url.searchParams.get("limit") ?? 1_000_000))
res.end(JSON.stringify({ count }))
} else {
res.end(JSON.stringify({ ok: true })) // stays instant during heavy work
}
})
server.listen(3000)
process.on("SIGINT", async () => { await Thread.terminate(countPrimes); process.exit(0) })
Process a batch with a thread pool
Distribute many CPU-bound jobs across a pool of workers sized to the machine’s cores. (full example)
import { availableParallelism } from "node:os"
import { Pool, spawn, Worker } from "threadsx"
const pool = Pool(
() => spawn(new Worker(new URL("./primes.worker.mjs", import.meta.url))),
Math.max(1, availableParallelism() - 1)
)
for (const limit of [500_000, 1_000_000, 1_500_000, 2_000_000]) {
pool.queue(async countPrimes => {
console.log(limit, await countPrimes(limit))
})
}
await pool.completed()
await pool.terminate()
See the thread pools guide for the full Pool API.
Share one worker across browser tabs
A counter that every open tab increments together, with worker-initiated
broadcasts keeping all tabs’ UIs in sync. Uses a native SharedWorker where
available and threadsx’s BroadcastChannel fallback elsewhere.
(full example)
// main.mjs — every tab runs this and reaches the SAME worker instance
import { spawnShared, Thread } from "threadsx"
const counter = await spawnShared(
({ shared }) => shared
? new SharedWorker("./counter.worker.js", { name: "shared-counter" })
: new Worker("./counter.worker.js"),
{ name: "shared-counter" }
)
Thread.broadcasts(counter).subscribe(({ count }) => {
document.getElementById("count").textContent = count
})
document.getElementById("increment").onclick = () => counter.increment()
// counter.worker.mjs
import { exposeShared } from "threadsx/worker"
let count = 0
const { broadcast } = exposeShared({
increment() {
count += 1
broadcast({ count }) // update every connected tab
return count
}
})
See the shared workers guide for lifecycle, the fallback transport, and failover semantics.