Communicate with a Web Worker using Promises, allowing transferList
npm install promise-worker-transferablepromise-worker-transferable 
====
Modified version of promise-worker library that supports object transferring. Possibly works slower than original for not transferable messages.
As mentioned here, promise-worker library will not get support for blobs and transferables. So here promise-worker-transferable goes.
Goals:
* Tiny footprint (~2.5kB min+gz)
* Assumes you have a separate worker.js file (easier to debug, better browser support)
* Removed from promise-worker and no longer true: JSON.stringifys messages for performance
* Instead, it's now possbile to transfer blobs, as well as attach transferList array to transfer objects, which works much faster for larger objects.
Live examples:
* Web Workers
* Service Workers
Usage
---
Install:
npm install promise-worker-transferable
Inside your main bundle:
``js
`
// main.js
var PromiseWorker = require('promise-worker-transferable');
var worker = new Worker('worker.js');
var promiseWorker = new PromiseWorker(worker);
promiseWorker.postMessage('ping').then(function (response) {
// handle response
}).catch(function (error) {
// handle error
});
// With transferList
promiseWorker.postMessage(pingImageData, [pingImageData.data.buffer]) // pongImageData transferred from main to worker
.then(function (response) {
// handle response
}).catch(function (error) {
// handle error
});
worker.js
Inside your bundle:
`
js
`
// worker.js
var registerPromiseWorker = require('promise-worker-transferable/register');
registerPromiseWorker(function (message) {
return 'pong';
});
// With transferList
registerPromiseWorker(function (message, withTransferList) {
return withTransferList(pongImageData, [pongImageData.data.buffer]); // pongImageData transferred from worker to main
});
require()
Note that you two separate APIs, so the library is split
worker.js
between the and main file. This keeps the total bundle size smaller.
`
$3
The message you send can be any object, array, string, number, etc.:
js
`
// main.js
promiseWorker.postMessage({
hello: 'world',
answer: 42,
"this is fun": true
}).then(/ ... /);
`
js
`
// worker.js
registerPromiseWorker(function (message) {
console.log(message); // { hello: 'world', answer: 42, 'this is fun': true }
});
`
$3
Inside of the worker, the registered handler can return either a Promise or a normal value:
js
`
// worker.js
registerPromiseWorker(function () {
return Promise.resolve().then(function () {
return 'much async, very promise';
});
});
`
js
`
// main.js
promiseWorker.postMessage(null).then(function (message) {
console.log(message): // 'much async, very promise'
});
`
Promise can return withTransferList as well:
js
`
// worker.js
registerPromiseWorker(function (_, withTransferList) {
return Promise.resolve().then(function () {
return withTransferList(pongImageData, [pongImageData.data.buffer]); // pongImageData transferred to webworker
});
});
`
js
`
// main.js
promiseWorker.postMessage(null).then(function (message) {
// message contains pongImageData
});
`
$3
Any thrown errors or asynchronous rejections from the worker will
be propagated to the main thread as a rejected Promise. For instance:
js
`
// worker.js
registerPromiseWorker(function (message) {
throw new Error('naughty!');
});
`
js
`
// main.js
promiseWorker.postMessage('whoops').catch(function (err) {
console.log(err.message); // 'naughty!'
});
console.error()
Note that stacktraces cannot be sent from the worker to the main thread, so you
will have to debug those errors yourself. This library does however, print
messages to , so you should see them there.
`
$3
If you need to send messages of multiple types to the worker, just add
some type information to the message you send:
js
`
// main.js
promiseWorker.postMessage({
type: 'en'
}).then(/ ... /);
promiseWorker.postMessage({
type: 'fr'
}).then(/ ... /);
`
js
`
// worker.js
registerPromiseWorker(function (message) {
if (message.type === 'en') {
return 'Hello!';
} else if (message.type === 'fr') {
return 'Bonjour!';
}
});
`
$3
Communicating with a Service Worker is the same as with a Web Worker.
However, you have to wait for the Service Worker to install and start controlling the page. Here's an example:
js
`
navigator.serviceWorker.register('sw.js', {
scope: './'
}).then(function () {
if (navigator.serviceWorker.controller) {
// already active and controlling this page
return navigator.serviceWorker;
}
// wait for a new service worker to control this page
return new Promise(function (resolve) {
function onControllerChange() {
navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
resolve(navigator.serviceWorker);
}
navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);
});
}).then(function (worker) { // the worker is ready
var promiseWorker = new PromiseWorker(worker);
return promiseWorker.postMessage('hello worker!');
}).catch(console.log.bind(console));
`
Then inside your Service Worker:
js
`
var registerPromiseWorker = require('../register');
registerPromiseWorker(function (msg) {
return 'hello main thread!';
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); // activate right now
});
new PromiseWorker(worker)
Browser support
----
* Chrome
* Firefox
* Safari 8+
* IE 10+
* Edge
* iOS 8+
* Android 4.4+
If a browser doesn't support Web Workers but you still want to use this library,
then you can use pseudo-worker.
For Service Worker support, Chrome 40 and 41 are known to be buggy (see #9), but 42+ are supported.
This library is not designed to run in Node.js.
API
---
$3
####
PromiseWorker
Create a new , using the given worker.
worker
* - the Worker or PseudoWorker to use.
PromiseWorker.postMessage(message, optionalTransferList)
####
message
Send a message to the worker and return a Promise.
* - object - required
optionalTransferList
* The message to send.
* - array of objects to transfer, just as in usual Worker.postMessage.
registerPromiseWorker(function)
* returns a Promise
$3
Register a message handler inside of the worker. Your handler consumes a message
and returns a Promise or value.
####
function`
*
* Takes a message and withTransferList function, returns a Promise or a value.
Value can be wrapped with withTransferList. withTransferList gets value and transferList.
Testing the library
---
First:
npm install
Then to test in Node (using an XHR/PseudoWorker shim):
npm test
Or to test manually in your browser of choice:
npm run test-local
Or to test in a browser using SauceLabs:
npm run test-browser
Or to test in PhantomJS:
npm run test-phantom
Or to test with coverage reports:
npm run coverage