async-worker-ts
TypeScript icon, indicating that this package has built-in type declarations

1.0.14 • Public • Published

async-worker-ts 🔱

A type-safe package designed to simplify the usage of worker threads on the server or browser.


Usage:

import createWorker, { task } from "async-worker-ts"

const worker = createWorker({
  calculatePi: (iterations: number) => {
    let pi = 0
    for (let i = 0; i < iterations; i++) {
      pi += Math.pow(-1, i) / (2 * i + 1)
    }
    return pi * 4
  },

  todos: {
    get: () => {
      // ...
    },
    add: () => {
      // ...
    },
    delete: () => {
      // ...
    },
  },
})

await worker.calculatePi(1_000_000).then(console.log) // 3.14159265258979
await worker.exit() // terminates the worker thread

Accessing procedures within procedures:

import useWorker from "async-worker-ts"

const worker = useWorker({
  /**
   * NB; the 'this' keyword is available in procedures declared as anything
   * but arrow functions and can be used to access other procedures.
   */
  addRandomNumbers: function () {
    const a = this.randomNumber()
    const b = this.randomNumber()
    return a + b
  },
  randomNumber: () => {
    return Math.random() * 42
  },
})

Emitting data via Tasks:

import useWorker, { task } from "async-worker-ts"

const worker = useWorker({
  calculatePi: task(function (iterations: number) {
    let pi = 0
    for (let i = 0; i < iterations; i++) {
      pi += Math.pow(-1, i) / (2 * i + 1)

      // the "this" keyword in the context of a task refers to the task itself.
      if (i % (iterations / 100) === 0) this.emit("progress", i / iterations)
    }
    return pi * 4
  }),
})

await worker
  .calculatePi(1_000_000)
  .on("progress", console.log) // 0.01, 0.02, ...
  .then(console.log) // 3.14159265258979

Concurrency and batching:

import useWorker from "async-worker-ts"

const worker = useWorker({
  calculatePi: (iterations: number) => {
    let pi = 0
    for (let i = 0; i < iterations; i++) {
      pi += Math.pow(-1, i) / (2 * i + 1)
    }
    return pi * 4
  },
})

/**
 * We can use the 'concurrently' method to run a task from the worker
 * client in a new auto-disposed worker thread.
 */
worker.concurrently((w) => w.calculatePi(1_000_000)) // 3.14159265258979

/** or: */
for (let i = 0; i < 4; i++) {
  worker.concurrently((w) => w.calculatePi(1_000_000))
}

Transferables:

import useWorker, { transfer } from "async-worker-ts"

const worker = useWorker({
  drawToCanvas: (OffscreenCanvas) => {
    // ... do things with the canvas here as if we were on the main thread
  },
})
const canvas = document.createElement("canvas")
const offscreenCvs = canvas.transferControlToOffscreen()

/**
 * By passing the argument through the 'transfer' function, we flag it as an
 * transferable. This is the equivalent of calling 'postMessage' with the
 * second argument being an array containing the argument.
 */
worker.drawToCanvas(transfer(offscreenCvs))

Dynamic imports and module resolution:

Importing modules requires a bundler for module resolution because procedures are serialized and executed in a different scope, rendering relative paths useless. I created awt-bundler as a simple bundler for using this package with Node.

someModule.ts:

export const someFunction = () => {
  // ...
}

myWorker.ts:

import useWorker, { AWTClientBuilder } from "async-worker-ts"

const worker = useWorker({
  doSomething: async () => {
    const { someFunction } = await import("./someModule.ts")
    return someFunction()
  },
})

// or:

const workerWithCachedImports = new AWTClientBuilder()
  .withImportCache(async () => {
    const { someFunction } = await import("./someModule.js")
    return { someFunction }
  })
  .build(function ({ someFunction }) {
    return {
      doSomething: () => {
        return someFunction()
      },
    }
  })

God help your CPU. 🙏

Richard Ayoade using async-worker-ts

Package Sidebar

Install

npm i async-worker-ts

Weekly Downloads

4

Version

1.0.14

License

GNUV3

Unpacked Size

28.2 kB

Total Files

22

Last publish

Collaborators

  • ra93