npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

worker-island

v1.0.1

Published

Seamlessly offload heavy CPU logic, functions, or classes into background Web Workers using Proxies

Readme

🏝️ Worker Island

npm version license

Seamlessly offload heavy CPU logic, functions, or classes into background threads using ES6 Proxies. Zero configuration. Zero dependencies. Fully typed. Works natively in the Browser and Node.js! 🚀


✨ Features

  • 🧮 Transparent Proxies - Call background functions, construct classes, or access object methods as if they were local.
  • 🌊 Async Generator RPC Streaming - Stream progress, status updates, or large datasets live from worker threads with native async * and yield support. Supports backpressure and early loop breaks (break).
  • 🏊‍♂️ Dynamic Adaptive Worker Pooling - Load balance tasks across a bounded worker pool. Automatically caps background threads to system concurrency limits (navigator.hardwareConcurrency / os.cpus()) to protect device battery and memory.
  • Zero-Copy Transferables Auto-Detection - Automatically detects and transfers transferrable objects (like ArrayBuffer, typed arrays, and MessagePort) without costly cloning overhead.
  • 💥 Transparent Error Boundaries - Catches worker-side errors, preserves custom fields/callstacks, and reconstructs them with a custom [Worker Boundary] trace on the main thread.
  • 🧹 Explicit Resource Management - Ready for TypeScript 5.2+ using declarations with native [Symbol.dispose] and .terminate() hooks.
  • 📦 Dual ESM & CommonJS Build - Published with native type definitions and package exports optimized for modern module systems and Node.js.

📦 Installation

npm install worker-island

🚀 Quick Start & Examples

1. Standalone Function 🧮

Offload a CPU-heavy computation so it doesn't freeze the user interface.

import { workerIsland } from 'worker-island';

// 1. Define your heavy CPU logic
function heavyFibonacci(n: number): number {
  if (n <= 1) return n;
  return heavyFibonacci(n - 1) + heavyFibonacci(n - 2);
}

// 2. Wrap it in a workerIsland
const asyncFibonacci = workerIsland(heavyFibonacci);

// 3. Call it asynchronously from the main thread!
const result = await asyncFibonacci(42); 
console.log(`Fibonacci(42) = ${result}`); // Runs on a background thread!

// Clean up when done
asyncFibonacci.terminate();

2. Stateful Class Instances with Constructor Parameters 🏗️

Instantiate classes inside a background thread and keep their internal state isolated.

import { workerIsland } from 'worker-island';

class IslandCalculator {
  private multiplier: number;

  constructor(multiplier: number) {
    this.multiplier = multiplier;
  }

  calculate(n: number): number {
    return n * this.multiplier;
  }
}

// 1. Wrap the class in workerIsland
const ActiveCalculator = workerIsland(HeavyCalculator);

// 2. Instantiate with constructor parameters
const calculator = new ActiveCalculator(5); // multiplier = 5

// 3. Methods are automatically mapped to return Promises
const result = await calculator.calculate(10);
console.log(result); // 50 (runs inside the background worker)

calculator.terminate();

3. Live Progress & Streaming via Async Generators 🌊

Stream long-running processes or chunks of data sequentially from background workers using standard for await...of loops.

import { workerIsland } from 'worker-island';

class FileDownloader {
  async *downloadAndParse(url: string) {
    yield { status: 'Downloading', progress: 0.1 };
    await new Promise(r => setTimeout(r, 500));

    yield { status: 'Parsing chunk 1', progress: 0.5 };
    await new Promise(r => setTimeout(r, 500));

    yield { status: 'Finished', progress: 1.0 };
  }
}

const RemoteDownloader = workerIsland(FileDownloader);
const downloader = new RemoteDownloader();

// Stream live progress logs from the Web Worker!
for await (const event of downloader.downloadAndParse('https://example.com/data.csv')) {
  console.log(`[Main Thread] ${event.status}: ${(event.progress * 100).toFixed(0)}%`);
}

// Memory and thread contexts are fully cleaned up!
downloader.terminate();

💡 Early Abort Handling: If you exit the loop early (e.g. via break), worker-island automatically notifies the worker thread to clean up and terminate the underlying generator generator context, preventing leaks!


4. Zero-Copy Data Transfer (Transferables) ⚡

Avoid the overhead of structured cloning when working with large datasets like buffers.

import { workerIsland } from 'worker-island';

const processor = workerIsland({
  processBuffer(buf: ArrayBuffer): number {
    const view = new Uint8Array(buf);
    view[0] = 42;
    return buf.byteLength;
  }
});

const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10MB buffer
console.log(buffer.byteLength); // 10485760

// The buffer is automatically detected and transferred with zero copying
const size = await processor.processBuffer(buffer);

console.log(size); // 10485760
console.log(buffer.byteLength); // 0 (transferred, memory released on main thread!)

processor.terminate();

5. Dynamic Adaptive Worker Pooling 🏊‍♂️

Scale concurrently without choking the machine. Setting a pool size configures a global manager that load-balances tasks across a fixed number of threads using a Least-Busy scheduling algorithm.

import { workerIsland } from 'worker-island';

// Cap active background threads to 4
workerIsland.setPoolSize(4);

class TaskProcessor {
  async compute(id: number) {
    // heavy computing...
    return id * id;
  }
}

const RemoteProcessor = workerIsland(TaskProcessor);

// Spawn 20 calculator instances
const instances = Array.from({ length: 20 }, () => new RemoteProcessor());

// Computations are automatically load-balanced across only 4 background workers!
const results = await Promise.all(
  instances.map((instance, idx) => instance.compute(idx))
);

// Cleanup the pool when your app shuts down
workerIsland.clearPool();

6. Explicit Resource Management (using statement) 🧹

Using TypeScript 5.2+ or modern JS runtimes, you can declare worker islands with the using keyword to automatically terminate them when they go out of scope.

import { workerIsland } from 'worker-island';

function heavyWork() {
  // The worker island is automatically terminated when function scope exits!
  using fibInstance = workerIsland(heavyFibonacci);
  const result = await fibInstance(35);
  return result;
}

7. Transparent Error Boundaries 💥

If an exception occurs in a worker thread, it is serialized and re-thrown on the main thread with a combined stack trace mapping exactly where the exception was thrown in the worker.

try {
  await calculator.triggerError("Bad dynamic input!");
} catch (err: any) {
  console.error(err.message); // "Bad dynamic input!"
  console.error(err.customCode); // 404 (custom properties are fully preserved!)
  console.error(err.stack);
  /* 
  Prints stack trace showing both:
  - where it occurred inside the Web Worker
  - [Worker Boundary]
  - where it was captured on the main thread!
  */
}

📖 API Reference

workerIsland(target)

Wraps a target function, class constructor, or plain object and returns an asynchronous proxy interface.

  • Target: A function, class constructor, or object.
  • Returns: An asynchronous proxy where all methods and functions return a Promise or an AsyncIterableIterator.
  • The returned proxy also implements:
    • .terminate(): Terminates the background worker thread.
    • [Symbol.dispose]: Disposes of the worker when exiting a scope.

workerIsland.setPoolSize(limit: number)

Sets the maximum number of background worker threads that can be spawned globally. All proxies created afterward will share and load-balance across these threads.

workerIsland.clearPool()

Terminates and disposes of all active workers in the global pool.


🛠️ How It Works Under The Hood

  1. Proxy Capture: When you call workerIsland(target), an ES6 Proxy intercepts all constructor calls (new) and method calls (obj.method()).
  2. Code Serialization: The library serializes the target functions/classes to string representations, wrapping them in a worker environment wrapper.
  3. Environment Agnostic Bridge: It runs worker code via browser Blob Object URLs or Node's worker_threads evaluation dynamically depending on the current environment.
  4. Zero-copy Transfer System: Before invoking postMessage, it recursively scans arguments for Transferable objects and pipes them to the worker memory space with zero copy overhead.
  5. Sequential Async Iterators: For generators, it pipes sequential stream yields and listens to early-abort commands to close generators on both sides safely.

📄 License

MIT © Saurabh Patel