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 🙏

© 2024 – Pkg Stats / Ryan Hefner

threading-js

v1.0.6

Published

Small wrapper for web workers that allows for running tasks without having to serve a worker script to the client.

Downloads

15

Readme

threading-js

npm version travis build lgtm code quality

Small wrapper for browser Web Workers that simplfies running tasks and allows running without having to serve a worker script to the client.

Use

Simple example showing how to use a Thread to interleave two arrays together using a SharedArrayBuffer. Using basic arrays increases the run time due to copying the data. ArrayBuffer ownership can be transferred using the transferList parameter in run and postMessage.

The function being passed to the thread must be completely self-contained and only reference data in the passed 'context' object or loaded scripts. All data passed into the context object will be stringified to be copied.

With ES6 Imports

Example here

import Thread from '.../node_modules/threading-js/Thread.js'

// Operation functions
const interleave = (a, b, res) => {
  let i = 0
  while(true) {
    if (i >= a.length || i >= b.length) break

    res[2 * i + 0] = a[i]
    res[2 * i + 1] = b[i]
    i++
  }
  return res
}

const threadFunc = args => {
  const arr1 = args.arr1
  const arr2 = args.arr2
  const res = args.res

  postMessage('starting')
  const data = interleave(arr1, arr2, res)
  postMessage('done')

  return data
}

// Create thread
const thread = new Thread(threadFunc, { interleave })

// Create data
const ARRAY_LENGTH = 10000000
const arr1 = new Float32Array(new SharedArrayBuffer(ARRAY_LENGTH * 4))
const arr2 = new Float32Array(new SharedArrayBuffer(ARRAY_LENGTH * 4))
const sharedres = new Float32Array(new SharedArrayBuffer(ARRAY_LENGTH * 4 * 2))
for(let i = 0; i < ARRAY_LENGTH; i++) {
  arr1[i] = Math.random()
  arr2[i] = Math.random()
}

// Run the tests
console.time('main thread run')
interleave(arr1, arr2, sharedres)
console.timeEnd('main thread run')

console.time('initial thread run')
thread
    .run({ arr1, arr2, res: sharedres }, log => console.log(log))
    .then(res => {
        console.timeEnd('initial thread run')

        console.time('subsequent thread run')
        return thread.run({ arr1, arr2, res: sharedres }, log => console.log(log))
    })
    .then(res => {
        console.timeEnd('subsequent thread run')
    })

// main thread run: 30.962158203125ms
// starting
// done
// initial thread run: 111.95703125ms
// starting
// done
// subsequent thread run: 35.179931640625ms

With UMD

Example here

<script type="text/javascript" src="../umd/Thread.js"></script>
<script type="text/javascript" src="../umd/ThreadPool.js"></script>
<script type="text/javascript" src="../umd/ThreadQueue.js"></script>

<script>
  const Thread = window.Thread.default
  const thread = new Thread(...)

  // ...use the thread...
</script>

Getting the Best Performance

Data Clone Pitfalls

When basic Javascript objects are transferred between the UI thread and a Web Worker (via run() in this library), they are copied using the Structured Clone Algorithm, which introduces a significant overhead that can be so bad that it completely defeats the purpose of using a thread. Using shared or transferred buffers is preferable.

Transferable Objects and ArrayBuffers

Some objects can have their ownership transferred between the threads, removing the need for cloning the data and associated overhead. A buffer is transferred using the run() function in this library and passing the object into the transferList array. Once an object has been transferred it's no longer accessible from the original thread and must be explicitly transferred back using a call to postMessage(). If an item is not in the transferList, then it is copied.

SharedArrayBuffers

SharedArrayBuffers are not copied, but don't need to be in the transferList, either. These buffers can be read from multiple threads at once making them an ideal vessel for data processing and return objects. Synchronized writes, however, must be accounted for.

API

Thread

constructor(threadFunc, context, srcs)

The constructor takes a function to run, a dictionary of context data and functions for use in the thread function, and an array of remote source URLs to load libraries in from.

threadFunc is the function to run in the worker. The value returned by this function will be passed back as the result of the run. postMessage can be used in this, as well, to post intermediate results back to the main thread.

context is a shallow dictionary of data or functions to be injected into the web worker scope.

srcs is an array of script URLs to load from.

running

Whether or not the thread is running

ready

Whether or not the thread is ready

run(args, intermediateFunc, transferList)

Runs the thread function with the args value as an argument to the function.

intermediateFunc is a callback to recieve intermediate postMessage results from the function. Use the intermediate postMessage function to transfer items as there's no way to return a list of items to transfer from thread function.

transferList the equivelant of the postMessage transfer list argument. Note that items in the transfer list are automatically retured once the run is completed.

Returns a promise.

cancel()

Cancels the current run and prepares for a new one.

dipose()

Disposes of the Thread data so it can't be used anymore.

ThreadPool

A thread pool for easily running many of the same type of task in parallel.

constructor(capacity, func, context, srcs, options)

Like the thread constructor, but takes a capacity as the first argument.

options.initializeImmediately = true: Creates all the threads immediately instead of lazily creating them so no intialization overhead is incurred.

ready

Whether the pool has inactive threads.

activeThreads

The number of currently inactive threads.

capacity

The total possible number of threads the pool can support.

run(...)

Get and use an available thread to run the requested task. Behaves like Thread.run, but returns null if there are not threads available in the pool.

dispose()

Dispose of all threads and data.

ThreadQueue

A helper class for creating a job queue and running through the tasks using as many threads to work as the capacity allows.

constructor(...)

Same as the ThreadPool constructor.

run(...)

Same as Thread.run.

dispose()

Same as ThreadPool.dispose