Skip to content
familiar logoFamiliarWorkers
Typed Web Worker pools with queuing, priorities, streaming, heartbeat, and testing utilities.
v0.0.14.1 KB gzip Browser · Node.js · SSR · Deno
createWorkercreateModuleWorkertasktransfercreateTestWorkerWorkerErrorWorkerTimeoutErrorWorkerTaskError +4 more →

Why Familiar?

Raw Web Workers require blob-URL boilerplate, untyped postMessage/onmessage pairs, and no built-in pooling, timeouts, or cancellation.

ts
// Before — raw Web Worker
const blob = new Blob([`onmessage = (e) => postMessage(e.data * 2);`]);
const rawWorker = new Worker(URL.createObjectURL(blob));
rawWorker.postMessage(21);
rawWorker.onmessage = (e) => console.log(e.data); // 42 — untyped, no await, no error handling

// After — familiar
import { createWorker, task } from '@vielzeug/familiar';
const double = task<number, number>((n) => n * 2);
const typedWorker = createWorker(double);
console.log(await typedWorker.run(21)); // 42 — typed, awaitable, error-safe
typedWorker.dispose();
FeatureWorkerComlinkworkerpool
Bundle size4.1 KB~2 kB~10 kB
Worker pools
Typed payloadsPartial
Timeout support
Priority queue
AbortSignal Queued tasks
Streaming runStream()
Heartbeat Auto for inline workers
Typed errors instanceof WorkerTimeoutError etc.
Testing utilities
Module workers createModuleWorker
Zero dependencies

Use Worker when you need typed, awaitable Web Workers with pooling, priorities, timeouts, streaming, and cancellation.

Consider Comlink if you only need a simple typed RPC proxy over a single Worker without pooling, priority, or timeout requirements.

Installation

sh
pnpm add @vielzeug/familiar
sh
npm install @vielzeug/familiar
sh
yarn add @vielzeug/familiar

Quick Start

ts
import { createWorker, task, WorkerTimeoutError, WorkerQueueFullError } from '@vielzeug/familiar';

// Wrap the function with task() to mark it as self-contained (safe to serialize)
const sum = task<number[], number>((nums) => nums.reduce((a, b) => a + b, 0));

// Single worker — processes one task at a time
const worker = createWorker(sum);
console.log(await worker.run([1, 2, 3, 4, 5])); // 15
worker.dispose();

// Worker pool — 4 concurrent slots with a timeout
const upper = task<string, string>((text) => text.toUpperCase());
const pool = createWorker(upper, { concurrency: 4, timeout: 5000 });
const items = ['alpha', 'beta', 'gamma', 'delta'];
const results = await Promise.all(items.map((item) => pool.run(item)));
pool.dispose();

// Priority — higher values run first when tasks queue up
await pool.run(urgentTask, { priority: 10 });

// Typed errors — precise instanceof checks
try {
  await pool.run(input, { timeout: 100 });
} catch (err) {
  if (err instanceof WorkerTimeoutError) console.error(`Timed out after ${err.timeoutMs}ms`);
  if (err instanceof WorkerQueueFullError) console.error(`Queue full (max ${err.maxQueue})`);
}

Features

  • Type-safe — payload types flow from TaskFn declaration to every run() call
  • Web Worker backed — CPU-bound work runs off the main thread, no jank
  • Pool support — create N workers via the concurrency option with built-in queuing
  • Priority queue — pass priority per-run; higher values run first with FIFO tiebreaking
  • Timeout support — pool-level or per-run timeout rejects with WorkerTimeoutError
  • Heartbeat monitoringheartbeatTimeout kills tasks that stop responding, with auto-heartbeats for inline workers
  • AbortSignal — cancel queued tasks with the standard AbortController API
  • StreamingrunStream() for tasks that yield multiple partial results
  • Batchbatch() runs inputs through the pool and yields results ordered or as-completed
  • Task groupsgroup() ties related tasks to a shared abort and drain lifecycle
  • Transferables — move large buffers to the Worker without a structured-clone copy
  • Prime — pre-initialize worker slots to eliminate first-task latency
  • Metricsactive, queued, utilization, completed, failed counters for observability
  • Typed error hierarchyWorkerTimeoutError, WorkerTaskError, WorkerQueueFullError, and more
  • [Symbol.dispose]using keyword support (ES2025 explicit resource management)
  • Module workerscreateModuleWorker loads a real .js/.ts module file as the Worker
  • Testing utilitiescreateTestWorker runs tasks in-process with call recording
  • Zero dependencies — no supply chain risk, minimal bundle size

Documentation

See Also

  • Arsenal — utility functions useful inside self-contained task functions
  • Ripple — pair with reactive signals to drive UI from worker pool metrics
  • Herald — emit typed events from worker task functions back to the main thread