yai

YaiWorker

Ultra-lightweight WebWorker manager (<1KB gzipped) with zero build tools, native ES modules, and seamless YEH event integration.


πŸš€ Quick Start

npm install @yaijs/core
import YaiWorker from '@yaijs/core/worker';

// One-shot computation
const result = await YaiWorker.run(
  (data) => data.items.filter(x => x.active).map(x => x.value),
  { items: [...] }
);

πŸ“– Core Concepts

1. Serialized Task Execution

Pass any pure function β€” it’s automatically serialized and runs in a WebWorker.

const worker = new YaiWorker(
  (inputData, taskId) => {
    // No DOM access here! Pure computation only.
    return inputData.map(x => x * 2);
  },
  { targetElement: button }
);

const result = await worker.start([1, 2, 3]);

⚑ Performance & Benchmarks

YaiWorker handles high-throughput mathematical transformations, deep arrays, and data serialization entirely off the main thread.

Below is a live execution log crunching 1 Billion sequential iterations without losing a single frame of DOM animation or blocking UI event interactions:

YaiWorker 1 Billion Iterations Benchmark


2. YEH Event Integration

Results bubble as native CustomEvents from your target element.

const worker = new YaiWorker(heavyTask, { targetElement: button });

const yeh = new YEH({
  '#my-button': [{ type: 'worker:success', handler: 'onComplete' }]
});

// Or native DOM
button.addEventListener('worker:success', (e) => {
  console.log('Result:', e.detail.payload);
});

3. Progress Updates

Your worker can send progress reports using the provided taskId. The onProgress callback receives the exact payload you send from the worker.

const worker = new YaiWorker(async (data, taskId) => {
  for (let i = 0; i <= 100; i++) {
    // Send progress update with the taskId from the second parameter
    self.postMessage({ taskId: taskId, status: 'progress', payload: i });
    await new Promise(r => setTimeout(r, 10));
  }
  return 'done';
}, { onProgress: (progressValue) => console.log(`Progress: ${progressValue}%`) });

πŸŽ›οΈ API Reference

new YaiWorker(task, options)

Parameter Type Description
task Function \| string Pure function to run in worker
options.mode 'transient' \| 'persistent' Default: 'transient' (auto-cleanup)
options.targetElement HTMLElement Dispatch CustomEvent from this element
options.importScripts string[] External scripts to load in worker
options.transferables ArrayBuffer[] Zero-copy transfer list
options.onProgress Function Progress callback
options.abortSignal AbortSignal External cancellation
options.allowThis boolean Allow this references (risky)

YaiWorker.run(task, inputData, options)

Static one-shot execution. Auto-terminates.

worker.start(inputData, transferables)

Returns Promise<result>.

worker.terminate()

Kills worker, revokes blob URL, rejects pending promise with AbortError.


🧩 Integration with YEH

YaiWorker dispatches native CustomEvents on your targetElement:

Event Detail property When
worker:success { taskId, payload, originElement } Computation completes
worker:error { taskId, payload, originElement } Worker throws

YEH listens to these natively β€” no extra wiring needed.


πŸ”§ Advanced Patterns

Persistent Worker (Stateful Background Task)

For persistent workers, state must live on the worker’s global scope (self), allowing consecutive .start() calls to mutate it.

const worker = new YaiWorker(
  async (inputData, taskId) => {
    // Initialize state on the worker's global scope if it doesn't exist
    self.workerState = self.workerState ?? 0;
    self.workerState += inputData;
    return self.workerState;
  },
  { mode: 'persistent' }
);

await worker.start(5);  // returns 5
await worker.start(3);  // returns 8
await worker.start(10); // returns 18

Zero-Copy with Transferables

const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10MB
const result = await YaiWorker.run(
  (buffer) => new Uint8Array(buffer).reduce((a,b) => a + b, 0),
  buffer,
  { transferables: [buffer] }
);
// buffer is now detached on main thread

CSP-Restricted Environments (Chrome Extensions)

Place /assets/yai-worker-bridge.js in your public folder. Detection is automatic.


πŸ§ͺ Live Demo

DOM-to-WebWorker Event Bridge on JSFiddle β€” Type to trigger prime number computation off the main thread. YaiWorker Demo - Self-calibrating progress bar


πŸ“š Deep Dives


πŸ“¦ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Main       β”‚     β”‚  YaiWorker   β”‚     β”‚  WebWorker  β”‚
β”‚  Thread     │────▢│  (Blob URL)  │────▢│  (Isolated) β”‚
β”‚             β”‚     β”‚              β”‚     β”‚             β”‚
β”‚  YEH ◀──────│─────│ CustomEvent  │◀────│ postMessage β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“„ License

MIT Β© YaiJS


πŸ† Stress Test Results

Iterations Time UI Clicks Result
1,000,000,000 2m 29s 164 βœ… Stable