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

workerproxy

v0.3.3

Published

Proxies function calls to web workers.

Downloads

10

Readme

Worker Proxy

This is a package to make it easy to proxy calls between a web app and one or more HTML5 Web Workers.

To use it, you just wrap the Worker instance with this package:

var proxy = workerproxy(new Worker('my-worker.js'));
// Note: This might fail in browsers that don't support Harmony proxies.
// See the easy fix and explanation further down.
proxy.greet('Blixt', function (err, message) {
  if (err) alert('Oopsies! ' + err.message);
  else alert(message);
});

For the Worker to understand calls, you also need to wrap the object that has the functions you want to call in the Worker code:

// In my-worker.js:
workerproxy({
  greet: function (name, callback) {
    callback(null, 'Hello, ' + name + '!');
  }
});

As you can see, the functions in the Worker are always expected to call callbacks. Even though this may seem unnecessary at first, the thinking is that since the calls between the app and the Worker will always be done asynchronously, it's best to model your code around that fact. The callbacks are in the Node.js style, which means they take an error as the first argument, then any number of success values.

Helper options

If you are writing a very simple Worker and don't want to have to think about callbacks, you can enable auto callbacks (and automatic catching of errors):

// In my-worker.js:
var options = {autoCallback: true, catchErrors: true};
workerproxy({
  greet: function (name) {
    if (!name) throw new Error('No name specified!');
    return 'Hello, ' + name + '!';
  }
}, options);

Browsers that don't support Harmony Proxies

If you want to support browsers that don't yet support Harmony Proxies, you may need to do some extra work. While workerproxy will let the app know what functions it has available, that will take a few milliseconds to propagate. So if you try to call the proxy immediately, it may fail. The solution to this is to specify the names of the functions you want to be able to call immediately:

// In your web app:
var proxy = workerproxy(new Worker('my-worker.js'), {
  functionNames: ['greet']
});

// This will now work even if the browser doesn't support Proxy.
proxy.greet('Blixt', function (err, message) {
  if (err) alert('Oopsies! ' + err.message);
  else alert(message);
});

Transferable objects

This package also supports transferable objects both ways. To mark an object for transfer, call the transfer method on the function that you would normally call (the method on the proxy for owner→worker and the callback for worker→owner). Then pass in the list of objects that you want to mark as the first argument, followed by the arguments you would normally pass in.

Here's a short example:

var api = require('workerproxy')(new Worker('worker.js'));

var buffer = new ArrayBuffer(100);
api.fillBuffer.transfer([buffer], buffer, function (err, buffer) {
  var array = new Uint8Array(buffer);
  console.log('Got buffer back:', array);
});

The worker.js file would look like this:

require('workerproxy')({
  fillBuffer: function (buffer, callback) {
    var array = new Uint8Array(buffer);
    for (var i = 0; i < array.length; i++) {
      array[i] = Math.random() * 255;
    }
    callback.transfer([buffer], null, buffer);
  }
});

Distribution of calls to multiple Workers

The last major feature of this package is that it supports taking a list of Workers. It will then distribute your calls between the Workers so that the first available Worker will get it (a Worker is considered available once it has called the callback function):

// In your web app:
var proxy = workerproxy([
  new Worker('my-worker.js'),
  new Worker('my-worker.js'),
  new Worker('my-worker.js')
]);

All calls will now be distributed between the three Workers. Obviously you want to ensure that all Workers can handle the calls and return the same type of data.

In some cases you may want to send the same call to all workers, and for that you can use the broadcast method on the function that you would normally call:

proxy.greet.broadcast('Blixt', function (err, message) {
  // This will be called once for every worker!
  console.log(message);
});

Installing with NPM

npm install --save workerproxy

Examples

Vanilla JavaScript

See the examples directory for some simple examples.

CommonJS

To call functions in a worker, wrap it with the workerproxy package, then call methods on the returned object as you normally would. Note that the last argument should always be a callback that takes an error argument followed by any number of values.

var api = require('workerproxy')(worker);
api.greet('World', function (err, response) {
  console.log('Worker said:', response);
});

Here's how you define the API in the worker file. Note that the last argument will always be a function to call when you want to return a value, even if your function is synchronous. This is so that the API maps 1:1 between how it is defined and how it is called.

require('workerproxy')({
  greet: function (name, callback) {
    callback(null, 'Hello, ' + name + '!');
  }
});

Options

Since there are two sides to the worker proxy, the set of options depends on which "side" you're setting up.

Options in web app

functionNames (default [])

A list of function names that are specified in the Worker. The reason this option exists is so that we can support browsers that don't have the Harmony Proxy object, which allows creating getters for properties that don't exist on an object. The names in functionNames will be added to a fake proxy object which is then returned, so that you can call those functions.

Note that the full list of function names will be added to the fake proxy object automatically, but in an asynchronous manner. So if you want to guarantee that the functions are available synchronously, use this option.

timeCalls (default false)

Whether to log the time it takes for calls to finish. This requires that the browser supports console.time and console.timeEnd.

Options in Worker

autoCallback (default false)

Automatically call the callback with the return value of the function. Note that the callback will always be called (unless an exception is thrown) even if you already called it earlier in your function, or didn't return a value (then it will be called with undefined).

If you want to prevent this behavior for a single function, you can call callback.disableAuto() in that function:

workerproxy({
  greet: function (name) {
    return 'Hello, ' + name + '!';
  },

  getName: function (id, callback) {
    // We can't return a value immediately, so disable auto callback.
    callback.disableAuto();

    lookupUser(id, function (err, info) {
      callback(err, info.name);
    });
  }
}, {autoCallback: true});

catchErrors (default false)

Catch errors in proxied functions and automatically respond with an error callback instead of throwing the error in the worker.

Example using catchErrors:

// worker.js

var store = {};

var functions = {
  get: function (key, callback) {
    if (!store.hasOwnProperty(key)) throw new Error('Key not found');
    callback(null, store[key]);
  },
  set: function (key, value, callback) {
    if (key in store && !store.hasOwnProperty(key)) {
      throw new Error('Invalid key');
    }

    store[key] = value;
    callback(null);
  }
};

// CommonJS:
require('workerproxy')(functions, {catchErrors: true});

// Vanilla JavaScript:
createWorkerProxy(functions, {catchErrors: true});