multiworker

1.0.3 • Public • Published

Summary

MultiWorker is a wrapper around node's and the browser's native (web) worker API. Features include:

  • Post data to workers and use callbacks to handle results.
  • Queue processes across multiple worker threads.
  • Build workers from functions, instead of needing a separate JS file.

Installation

Install via NPM:

npm install --save multiworker

Then use in your script:

import MultiWorker from 'multiworker';

Or, include the script the old fashioned way to make the MultiWorker constructor available globally:

<script src="dist/multiworker.min.js"></script>

Usage

Basic usage

A MultiWorker instance is created with a function which is used as the code for the worker.

var worker = new MultiWorker(function () {
  self.receive = function (n) {
    self.return(n + 1);
  }
});

In order to interact with the worker, we use the post method. This triggers the self.receive function inside the worker, which returns a value with self.return.

worker.post(5, function (n) {
  console.log(n); // => 6
});

Both worker.post() in the main thread and self.return() and self.post() in the worker can receive an array of transfers as last argument, to support Transferables.

var worker = new MultiWorker(function () {
  self.receive = function (inputBuffer) {
    // Worker now has ownership of the input buffer
    var resultBuffer = inputBuffer
    self.return(resultBuffer, [resultBuffer]);
    // Ownership of the result buffer has been transferred to the main thread
  }
});
var inputBuffer = new ArrayBuffer(5);
worker.post(inputBuffer, function(resultBuffer) {
  // Main thread now has ownership of the result buffer
}, [inputBuffer]);
// Ownership of the input buffer has been transferred to the worker

Options

worker

When creating a MultiWorker instance, a function can be passed:

var worker = new MultiWorker(function () {
  self.receive = self.return; // Simply return the input
});

Alternatively, a filepath, URL, or a stringified IIFE can be used.

var worker = new MultiWorker('workers/example.js');

worker.post('foo', function () {
  // This post won't occur until example.js has been fetched and the worker ready.
});

The worker can also be defined in an options object:

var worker = new MultiWorker({
  worker: function () {
    self.receive = self.return; // Simply return the input
  }
});

The worker url can also be passed as first argument, and all other options in an object literal as second argument:

var worker = new MultiWorker('workers/example.js', { threads: 2 })

callback

A function to be called whenever a worker sends a value back to the main program via self.post or self.return.

var worker = new MultiWorker({
  worker:   function () {
    self.receive = self.return; // Simply return the input
  },
  callback: function (val) {
    console.log(val);
  }
});

worker.post(1); // The callback function above will log 1 in the console

If a callback is passed as an argument when the post request is made, then the default callback is not used.

var worker = new MultiWorker({
  worker:   function () {
    self.receive = self.return; // Simply return the input
  },
  callback: function (val) {
    console.log(val);
  }
});

worker.post(1, function (val) {
  alert(val); // The callback function above will not be used. 1 will be alerted.
});

threads

The number of workers to spawn. The default is 1.

Multiple web workers:

var worker = new MultiWorker({
  worker:  function () {
    self.receive = self.return; // Simply return the input
  },
  threads: 2
});

// The posts below are processed in parallel.
// There is a chance that the second post will return first.
worker
  .post(42)
  .post(11);

A single web worker:

var worker = new MultiWorker({
  worker:  function () {
    self.receive = self.return; // Simply return the input
  },
  threads: 1
});

// The posts below are processed in series.
worker
  .post(42)
  .post(11);

dependencies

An array of named functions that can be used globally in the workers. These functions must be named and not make references to data outside the function scope.

var worker = new MultiWorker({
  worker: function () {
    self.receive = function (n1, n2) {
        self.return(multiply(n1, n2) + add(n1, n2));
    }
  },
    dependencies: [
      function multiply(n1, n2) {
        return n1 * n2;
      },
      function add(n1, n2) {
        return n1 + n2;
      }
  ]
});

worker.post(10, 2, function (n) {
  console.log(n); // => 32
});

MultiWorker Methods

post([...args], [callback], [transfers])

Interact with a MultiWorker instance. This method accepts an arbitrary number of parameters, which the worker can access with the self.receive method.

A callback can be passed - this is used instead of any default callback that may have been defined when creating the worker instance.

var worker = new MultiWorker(function () {
  self.receive = function (n1, n2) {
    self.return(n1 + n2);
  }
});

worker.post(2, 2, function (result) {
  console.log(result); // => 4
});

terminate([callback | instant])

Terminates the MultiWorker instance. The instance can no longer be used once this method has been called.

// Wait for post to return, then terminate
worker.post(10).terminate();
// Wait for post to return, then terminate and run the callback
worker.post(10).terminate(function () {
  console.log('Worker terminated');
});
// Terminate instantly, without waiting for result from any pending posts
worker.post(10).terminate(true);

Worker Methods

A few methods are made available inside the workers. These are attached to the self object.

self.receive([...args])

Fired in response to calling post() on a MultiWorker instance. This is the start of any process from within a worker.

var worker = new MultiWorker(function () {
  self.receive = function (n1, n2) {
    self.return(n1 + n2);
  }
});

worker.post(2, 2, function (result) {
  console.log(result); // => 4
});

self.return([...args], [transfers])

Sends a response back to the main thread. This will be called inside of self.receive - see the code example for that method for usage.

self.post([...args], [transfers])

Similar to self.return, but will not mark the current task as finished. self.return must be called after all work is done in order to start processing the next item in the queue.

var worker = new MultiWorker({
  worker:   function () {
    self.receive = function () {
      var i = 100;

      // A pointless loop to demonstrate.
      // A real-world usage could be a progress bar.
      while (i--) {
        if (i) {
          self.post(i);
        } else {
          self.return(i);
        }
      }
    }
  },
  callback: function (n) {
    if (!this.done) {
      console.log('left to complete: ' + n);
    } else {
      console.log('Finished');
    }
  }
});


worker
  .post()
  .post(); // This second post won't execute until self.return is called in response to the previous post.

Developing

To continuously run the tests while editing, run

npm start

and open your browser on http://localhost:3000.

To build the standalone version, run

npm run build

To ensure correct code style and that the library runs both in node and browsers, run

npm test

License

This project is licensed under the ISC License - see the LICENSE.md file for details

Package Sidebar

Install

npm i multiworker

Weekly Downloads

0

Version

1.0.3

License

ISC

Unpacked Size

135 kB

Total Files

21

Last publish

Collaborators

  • ahocevar
  • dlevs