Package Entry Point
| Import | Purpose |
|---|---|
@vielzeug/workit | Main exports and types |
API At a Glance
| Symbol | Purpose | Execution mode | Common gotcha |
|---|---|---|---|
createWorker() | Create a typed worker or worker pool | Sync | Task functions must be self-contained |
worker.run() | Execute a typed task in a Worker | Async | Pass transferables for large buffers when possible |
createTestWorker() | Run worker tasks in-process for tests | Async | Use call recording assertions to verify behavior |
Package Exports
export { createWorker, WorkerError } from '@vielzeug/workit';
export type { RunOptions, TaskFn, WorkerErrorCode, WorkerHandle, WorkerOptions, WorkerStatus } from '@vielzeug/workit';
export { createTestWorker } from '@vielzeug/workit/test';
export type { TestWorkerHandle } from '@vielzeug/workit/test';Types
TaskFn
type TaskFn<TInput, TOutput> = (input: TInput) => TOutput | Promise<TOutput>;The signature for the task function passed to createWorker. Accepts a single typed input and returns a value or a Promise.
WorkerStatus
type WorkerStatus = 'idle' | 'running' | 'terminated';| Value | Meaning |
|---|---|
'idle' | All worker slots are free |
'running' | One or more slots are executing a task |
'terminated' | dispose() was called |
WorkerOptions
type WorkerOptions = {
concurrency?: number | 'auto';
maxQueue?: number | 'auto';
timeout?: number;
};concurrency:number | 'auto', defaults to1.'auto'usesnavigator.hardwareConcurrencywhen available.maxQueue:number | 'auto' | undefined. Queue capacity beforerun()rejects withWorkerErrorcode'queue_full'.'auto'resolves toconcurrency * 2.timeout:number | undefined. Milliseconds before a task rejects withWorkerErrorcode'timeout'.
RunOptions
type RunOptions = {
signal?: AbortSignal;
transferables?: Transferable[];
};signal:AbortSignal— cancel a queued task. In-flight tasks cannot be interrupted.transferables:Transferable[]— objects to move (not copy) to the worker thread.
WorkerHandle
type WorkerHandle<TInput, TOutput> = {
[Symbol.asyncDispose](): Promise<void>;
[Symbol.dispose](): void;
close(): Promise<void>;
readonly completed: number;
run(input: TInput, options?: RunOptions): Promise<TOutput>;
dispose(): void;
readonly concurrency: number;
readonly size: number;
readonly status: WorkerStatus;
readonly utilization: number;
};The return type of createWorker. See WorkerHandle Interface for per-member documentation.
createWorker
declare function createWorker<TInput, TOutput>(
fn: TaskFn<TInput, TOutput>,
options?: WorkerOptions,
): WorkerHandle<TInput, TOutput>;Creates a worker (or pool) that executes fn in a Web Worker. createWorker() is safe to call in any runtime, but run() requires a real Worker implementation and rejects with WorkerError when the Worker API is unavailable.
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | TaskFn<TInput, TOutput> | The task function. Must be self-contained — no closure over outer scope. |
options | WorkerOptions | Optional configuration (concurrency, maxQueue, timeout). |
Returns WorkerHandle<TInput, TOutput>.
Example
import { createWorker } from '@vielzeug/workit';
// Single worker
const worker = createWorker<string, string>((text) => text.toUpperCase());
// Pool of 4
const pool = createWorker<number, number>((n) => n ** 2, { concurrency: 4, maxQueue: 'auto', timeout: 3000 });WorkerHandle Interface
run(input, options?)
run(input: TInput, options?: RunOptions): Promise<TOutput>
Dispatches a task to the next available worker slot. If all slots are busy, the task is queued.
Rejects with:
WorkerErrorcode'queue_full'— ifmaxQueueis configured and the queue is already fullWorkerErrorcode'timeout'— iftimeoutis configured and the task exceeds itWorkerErrorcode'terminated'— ifdispose()was called before or during the taskWorkerErrorcode'task'— if the task function throwsDOMException(AbortError) — if the providedsignalis aborted before the task startsWorkerErrorcode'worker'— worker runtime/setup failures
WARNING
The task function is serialized via .toString() and runs in an isolated scope. It cannot close over variables from the surrounding module. Keep task functions entirely self-contained.
dispose()
dispose(): void
Terminates all worker threads and rejects any pending or in-flight tasks with WorkerError code 'terminated'. After calling dispose(), status becomes 'terminated' and further calls to run() reject immediately.
close()
close(): Promise<void>
Graceful shutdown. Waits until queued and in-flight tasks settle, then terminates all workers.
completed
readonly completed: number
Total number of successfully completed tasks since handle creation.
concurrency
readonly concurrency: number
The number of worker slots configured for this handle (always ≥ 1).
size
readonly size: number
Current queue depth (tasks waiting to start).
status
readonly status: WorkerStatus
The current state of the worker handle. See WorkerStatus.
utilization
readonly utilization: number
Current active-slot ratio from 0 to 1.
[Symbol.dispose]()
[Symbol.dispose](): void
Alias for dispose(). Enables the ES2025 explicit resource management using keyword:
{
using worker = createWorker<number, number>((n) => n * 2);
const result = await worker.run(21); // 42
} // automatically disposed hereError Model
Workit uses a single error class: WorkerError.
class WorkerError extends Error {
readonly code: WorkerErrorCode;
}Use instanceof WorkerError plus err.code for branching:
import { WorkerError } from '@vielzeug/workit';
try {
await worker.run(input);
} catch (err) {
if (err instanceof WorkerError && err.code === 'timeout') {
// task exceeded timeout
}
}Supported WorkerErrorCode values:
'invalid_options''queue_full''task''terminated''timeout''worker'
Testing Utilities
Import from the /test subpath — not included in the main bundle:
import { createTestWorker } from '@vielzeug/workit/test';
import type { TestWorkerHandle } from '@vielzeug/workit/test';createTestWorker
declare function createTestWorker<TInput, TOutput>(fn: TaskFn<TInput, TOutput>): TestWorkerHandle<TInput, TOutput>;Creates a TestWorkerHandle that runs fn in-process on the same thread and records successful calls. No Worker is ever spawned, so tests work in any environment.
TestWorkerHandle
type TestWorkerHandle<TInput, TOutput> = WorkerHandle<TInput, TOutput> & {
readonly calls: ReadonlyArray<{ input: TInput; output: TOutput }>;
};Extends WorkerHandle with:
| Member | Type | Description |
|---|---|---|
calls | ReadonlyArray<{ input, output }> | All successful run() calls in order. |
[Symbol.dispose]() | void | Same as dispose(). |