Does JSAR Support Web Workers? Complete Implementation Guide

Yes, JSAR provides a full Web Workers implementation that mirrors the browser Worker API while running on top of Node.js worker_threads.

The m-creativelab/jsar-runtime repository includes a self-contained worker system that simulates the DOM Worker environment in a Node.js-based runtime. This allows JavaScript code written for browser Workers to execute unchanged within the JSAR platform.

How JSAR Implements Web Workers

JSAR does not rely on browser-native Workers. Instead, it implements the entire Worker specification using Node.js threading primitives. The architecture bridges the Node.js worker_threads module with a browser-compatible API layer, complete with DOM events, script loading, and nested worker support.

The system is modularized across four key areas:

  • Worker lifecycle management – Handles construction, message routing, and termination
  • Entry point bootstrapping – Sets up the global scope inside the worker thread
  • Event system – Provides DOM-compatible MessageEvent and ErrorEvent objects
  • Resource loading – Integrates with JSAR's asset pipeline for script fetching

Core Components of the Worker System

WorkerImpl: The Public Interface

The [lib/webworkers/worker.ts](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/webworkers/worker.ts) file exports the WorkerImpl class, which implements the standard Worker interface. This class exposes onmessage, onerror, onmessageerror, and methods like postMessage() and terminate().

Key implementation details from the source:

  • Document requirement: The constructor checks for the existence of document to ensure Workers are only created within browser-like environments
  • Blob URL support: Detects blob: schemes and resolves underlying Blob sources via resolveObjectURL
  • Private initialization: The #initHandle() method wires Node's 'message', 'messageerror', and 'error' events to DOM-compatible event objects

When worker.start() is called, the class resolves the internal entry script (jsar-webworkers-entry.js) and spawns a Node WorkerThreads.Worker with a serialized WorkerRequest containing the script URL and base URI.

Entry Script and WorkerContext

The [lib/webworkers/entry.ts](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/webworkers/entry.ts) file serves as the bootstrap code executed inside each worker thread. Its responsibilities include:

  1. Mapping globalThis.postMessage to parentPort.postMessage for host communication
  2. Injecting __WorkerImpl into the global scope to enable nested workers (workers creating workers)
  3. Instantiating a WorkerContext (JSAR's DOM shim) to provide self and other globals
  4. Loading either inline script sources (from Blobs) or fetching external URLs via the resource loader

Event Handling

Standard DOM event objects are re-exported from [lib/webworkers/events.ts](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/webworkers/events.ts). The implementation provides:

  • ErrorEvent for uncaught exceptions
  • MessageEvent for data passing between threads

These align with the WHATWG Web Workers specification, ensuring that event handlers like worker.onmessage receive objects with data, origin, and ports properties.

Resource Loading

Workers share the same asset pipeline as the main JSAR runtime through [lib/runtime2/ResourceLoader.ts](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/runtime2/ResourceLoader.ts). The ResourceLoaderOnTransmute interface allows workers to fetch scripts and assets using the same resolution logic as the parent context, including support for custom protocols and transmutation hooks.

Creating and Using Workers in JSAR

Basic Worker Instantiation

To create a worker in JSAR, instantiate WorkerImpl with a script URL, register event handlers, and call start():

import { WorkerImpl } from 'jsar-runtime/lib/webworkers/worker';

// Create worker from a script file
const worker = new WorkerImpl('scripts/computation.js');

// Handle incoming messages
worker.onmessage = (event: MessageEvent) => {
  console.log('Received:', event.data);
};

worker.onerror = (event: ErrorEvent) => {
  console.error('Worker failed:', event.message, event.filename);
};

// Initialize the worker thread
worker.start();

// Send data to the worker
worker.postMessage({ type: 'CALCULATE', payload: [1, 2, 3] });

Nested Workers via __WorkerImpl

JSAR supports spawning workers from within workers using the hidden __WorkerImpl global injected by the entry script:

// Inside scripts/computation.js (running in worker context)
self.onmessage = (e) => {
  if (e.data.type === 'SPAWN_SUBWORKER') {
    // Create a nested worker
    const subWorker = new __WorkerImpl('scripts/sub-task.js');
    
    subWorker.onmessage = (msg) => {
      self.postMessage({ from: 'nested', result: msg.data });
    };
    
    subWorker.start();
    subWorker.postMessage(e.data.payload);
  }
};

This pattern enables parallel processing trees where parent workers delegate to child workers without blocking the main thread.

Inline Workers with Blob URLs

For dynamic script generation, JSAR supports the Blob URL pattern:

const workerScript = `
  self.onmessage = (e) => {
    const result = e.data.map(x => x * 2);
    self.postMessage(result);
  };
`;

const blob = new Blob([workerScript], { type: 'application/javascript' });
const blobUrl = URL.createObjectURL(blob);

const worker = new WorkerImpl(blobUrl);
worker.onmessage = (ev) => console.log('Doubled:', ev.data);
worker.start();
worker.postMessage([5, 10, 15]);

The WorkerImpl constructor detects the blob: protocol and extracts the underlying source code for execution in the worker context.

Summary

  • JSAR implements the complete Web Workers API using Node.js worker_threads as the underlying engine
  • The WorkerImpl class in lib/webworkers/worker.ts provides the standard Worker interface with DOM-compatible events
  • Workers can spawn nested workers using the __WorkerImpl global available in worker contexts
  • Script loading supports both external URLs and inline Blob sources through the integrated ResourceLoader
  • The implementation requires a DOM environment (checks for document) to maintain browser semantics

Frequently Asked Questions

Does JSAR support Web Workers?

Yes. JSAR includes a full Web Workers implementation that mirrors the browser API. The system uses Node.js worker_threads internally while exposing standard Worker methods like postMessage(), terminate(), and event handlers. The source code in lib/webworkers/worker.ts implements this interface completely.

Can workers spawn other workers in JSAR?

Yes, JSAR supports nested workers. When a worker script executes, the entry script (lib/webworkers/entry.ts) injects __WorkerImpl into the global scope. This allows code running inside a worker to instantiate child workers using new __WorkerImpl(url), enabling hierarchical parallel processing.

How does JSAR handle worker script loading?

JSAR uses its ResourceLoader system (from lib/runtime2/ResourceLoader.ts) to resolve worker scripts. The WorkerImpl constructor accepts standard URLs or Blob URLs. For Blob sources, the implementation resolves the underlying source code via resolveObjectURL. The entry script then either evaluates the inline source or fetches the external resource through the runtime's asset pipeline.

Is the JSAR Worker API compatible with standard browser Workers?

Yes. The implementation aims for compatibility with the WHATWG Web Workers specification. Event objects (MessageEvent, ErrorEvent), the self global scope, and method signatures match browser behavior. Code written for standard browser Workers typically runs in JSAR without modification, provided it does not rely on browser-specific APIs unavailable in the JSAR runtime.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →