workers
import { workers } from "@tynd/core/client";Isolated JS runtime on its own OS thread — JSON input / output.
spawn<I, O>(fn): Promise<Worker<I, O>>
const w = await workers.spawn((input: number[]) =>
input.reduce((a, b) => a + b, 0)
);fnmust be self-contained — no closure captures, no outer references.- Arguments and return value are JSON-serialized.
Worker<I, O> methods
run(input): Promise<O>
const sum = await w.run<number, number[]>([1, 2, 3, 4, 5]); // 15Serializes input, runs the function in the worker, returns the result.
terminate(): Promise<void>
Force-stop the worker.
await w.terminate();How it works under the hood
lite— spawns an isolatedrquickjs::Runtimeon a fresh OS thread. Eachrunserializes input to JSON, evaluates the function there, and sends the result back. No shared globals, no shared heap.full— wrapsBun.Workervia a data-URL worker script. Same surface, same serialization semantics.
Typical uses
- Heavy JSON parsing — 50 MB JSON blob that would block the main thread.
- Image / audio processing in pure JS — keep the UI responsive.
- Computation without an event loop — simulation loops, particle systems.
For Rust-backed compute (hashing, CSPRNG), prefer compute — it’s faster and doesn’t round-trip through JSON.
Notes
- No
SharedArrayBuffer/Atomicssupport in lite (QuickJS limitation). Use message passing (the worker’sruninput/output) instead. - Cannot import modules inside the worker function — everything it needs must be captured in the function body or serialized as input.
- Workers run on OS threads, not thread pools. Spawning dozens is wasteful. Use a small pool +
runtasks to it.
Example — parallel map
async function parallelMap<I, O>(
items: I[],
fn: (x: I) => O,
poolSize = 4,
): Promise<O[]> {
const pool = await Promise.all(
Array.from({ length: poolSize }, () => workers.spawn(fn)),
);
try {
const out = new Array<O>(items.length);
let idx = 0;
await Promise.all(pool.map(async (w) => {
while (idx < items.length) {
const i = idx++;
out[i] = await w.run(items[i]);
}
}));
return out;
} finally {
await Promise.all(pool.map((w) => w.terminate()));
}
}Related
- compute — Rust-native hashing and RNG (faster for those tasks).
- Streaming RPC — if you need to stream intermediate results.
Last updated on