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

uwork

v1.1.0

Published

Tiny webworker that doesn't need an external file

Downloads

8

Readme

uwork

Web workers made easy. Perfect for math intensive tasks as it uses the CPU in parallel:

CPU in async vs in parallel

Web workers are awesome and this project is taking a subset of that and making it trivial to implement. This is for functions that take N arguments, process them and then return a value once.

Getting started

Install with npm:

npm install uwork

Or include the script in your website:

<script src="https://cdn.jsdelivr.net/npm/uwork@1/uwork.js"></script>

Then create the work that you want performed and wrap it with a function called uwork. It can be either a sync or async function. Let's calculate Pi with the Monte Carlo method as an example:

// Create the piece of work to be performed
// It can be sync or async
const findPi = uwork((iterations = 10000) => {
  let inside = 0;
  for (var i = 0; i < iterations; i++) {
    let x = Math.random(), y = Math.random();
    if (x * x + y * y <= 1) inside++;
  }
  return 4 * inside / iterations;
});

Finally do the actual work and handle the returned promise:

// Run this inside an async context:
const pi = await findPi(200000000);

Regardless of whether the function you create is sync or async, the returned function of uwork() will always be async. This is the return order:

uwork(fn) => function(args) => Promise(value)

See demo in JSFiddle.

Options

There's only a single option so far: timeout (ms). Establish a maximum time for the web worker to perform some job, then the promise is rejected. If set to 0, false or a falsy value then there is no timeout. Defaults to undefined.

// Limit it to 10s
uwork.timeout = 10000;

// ...

Communication

To call your parallel function it's always the same way; pass the arguments to the returned function from uwork() and await for the return value:

const work = uwork(fn);
const result = await work(args);

Now, to send that result from within the fn(), you can return a value either from a sync or an async function. Since many math intensive processes are synchronous, this is a great way to unblock the main thread while doing heavy work in a secondary thread:

// Simple return for sync operations. This will be made parallel and thus async
var work = uwork(function intensive(args) {

  // heavy work here

  return 42;
});

Using Async/Await it also has a very clean syntax:

// Using promises
var work = uwork(async (number = 10000) => {

  // heavy work here

  return 42;
});

Note that the code above is equivalent to the following:

// Using promises
var findPi = uwork((number = 10000) => {
  return new Promise((resolve, reject) => {

    // heavy work here

    resolve(42);
  });
});

The coolest thing is that the function interface is compatible with normal Javascript code, you just wrap it around:

// Perform the work in a single thread but async
const work = async () => {

  // heavy work here

  return 42;
};

const res = await Promise.all([work(), work(), work(), work()]);
// Just wrap uwork() around it to make it parallel
const work = uwork(async () => {

  // heavy work here

  return 42;
});

const res = await Promise.all([work(), work(), work(), work()]);

Error handling

Follows standard promise error handling:

try {
  const pi = await findPi(20000);
} catch (error) {
  console.error(error);
}

To reject the operation in both ways you can either return an Error (which will be stringified, read extra section) or throw it:

const findPi = uwork((number) => {
  if (number === 0) {
    // return new Error('Cannot iterate 0 times');
    throw new Error('Cannot iterate 0 times');
  }

  // heavy work here
});

Extra

There are some things that you should know. While Web Workers are great, they also have limitations. The main ones [for practical purposes] are:

Functions should be self-contained

This won't work for example:

var external = whatever => whatever;

var worker = uwork(function(){
  return external('Peter');
});

This is a limitation of the way we simplify web workers. We are basically getting the function, converting it into a string, creating a virtual script and executing it there (not too different from eval).

Values should be able toString()

Both the arguments you are passing and the result of the operation.

Security

Treat this as if it was using eval() internally or dig into the code and edit this document if you know more than me.

Don't build anything dynamically (from the previous limitations is quite difficult anyway), just rely on this for math or CPU-intensive processes. Clean and validate your arguments.

Native workers

Native workers can communicate over time several messages, so this library is somewhat limiting that in exchange for a much simpler API. If you like this I recommend you dig into them.

Credit

Learned from (Blob() & URL.createObjectURL