From 90ca6fecfc73fab8a58514621d49234baf054215 Mon Sep 17 00:00:00 2001 From: Jeremy Scheff Date: Wed, 6 Nov 2019 10:06:03 -0500 Subject: [PATCH] Changelog and readme in anticipation of v4.0.0 --- CHANGELOG.md | 4 + README.md | 201 ++++++++++++++++++++++++++------------------------- TODO | 4 - 3 files changed, 108 insertions(+), 101 deletions(-) delete mode 100644 TODO diff --git a/CHANGELOG.md b/CHANGELOG.md index 715a977..dadd96a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v4.0.0, 2019-11-06 + +Split the old PromiseWorker class into two separate classes PWBHost and PWBWorker, so they can be included separately in main and worker bundles, leading to smaller bundle sizes. Savings seems to just be a couple kb per bundle, but every byte counts! + # v3.0.2, 2018-07-06 This should obviously print "true": diff --git a/README.md b/README.md index 443ab88..c6f1410 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ -promise-worker-bi [![Build Status](https://travis-ci.org/dumbmatter/promise-worker-bi.svg?branch=master)](https://travis-ci.org/dumbmatter/promise-worker-bi) -==== +# promise-worker-bi [![Build Status](https://travis-ci.org/dumbmatter/promise-worker-bi.svg?branch=master)](https://travis-ci.org/dumbmatter/promise-worker-bi) A small (~2 kB min+gz) and performant library for communicating with web workers and shared workers, using promises. Post a message from the browser to the worker, get a promise that resolves to the response. Post a message from the worker to the browser, get a promise that resolves to the response. And with shared workers, you can either broadcast to all browser tabs or send a message to a specific tab. This is based on [promise-worker](https://github.com/nolanlawson/promise-worker) which only allows you to send messages from the browser to the worker, not in reverse. This library allows both, using the exact same API, and has additional support for shared workers. -Usage ---- +## Usage Install: @@ -16,41 +14,47 @@ Inside your main bundle: ```js // main.js -var PromiseWorker = require('promise-worker-bi'); +import { PWBHost } from "promise-worker-bi"; -var worker = new Worker('worker.js'); -var promiseWorker = new PromiseWorker(worker); +var worker = new Worker("worker.js"); +var promiseWorker = new PWBHost(worker); // Only needed if you send messages from the worker to the host -promiseWorker.register(function (message) { - return 'pong2'; +promiseWorker.register(function(message) { + return "pong2"; }); -promiseWorker.postMessage('ping').then(function (response) { - // handle response 'pong' -}).catch(function (error) { - // handle error -}); +promiseWorker + .postMessage("ping") + .then(function(response) { + // handle response 'pong' + }) + .catch(function(error) { + // handle error + }); ``` Inside your `worker.js` bundle: ```js // worker.js -var PromiseWorker = require('promise-worker-bi'); +import { PWBWorker } from "promise-worker-bi"; -var promiseWorker = new PromiseWorker(); +var promiseWorker = new PWBWorker(); // Only needed if you send messages from the host to the worker -promiseWorker.register(function (message) { - return 'pong'; +promiseWorker.register(function(message) { + return "pong"; }); -promiseWorker.postMessage('ping2').then(function (response) { - // handle response 'pong2' -}).catch(function (error) { - // handle error -}); +promiseWorker + .postMessage("ping2") + .then(function(response) { + // handle response 'pong2' + }) + .catch(function(error) { + // handle error + }); ``` **Notice that except for initialization of the `promiseWorker` object, the API is identical in the browser and in the worker. Either one can initiate a message.** In all of the subsequent examples, `promiseWorker` initialization is omitted, so you can put the two blocks of code respectively in the worker and browser, or in the browser and worker. @@ -58,7 +62,7 @@ promiseWorker.postMessage('ping2').then(function (response) { And it's even better with async/await: ```js -const response = await promiseWorker.postMessage('ping2'); +const response = await promiseWorker.postMessage("ping2"); // response contains 'pong2' ``` @@ -67,15 +71,17 @@ const response = await promiseWorker.postMessage('ping2'); The message you send can be any object, array, string, number, etc. - anything that is serializable by the structured clone algorithm: ```js -promiseWorker.postMessage({ - hello: 'world', - answer: 42, - "this is fun": true -}).then(/* ... */); +promiseWorker + .postMessage({ + hello: "world", + answer: 42, + "this is fun": true + }) + .then(/* ... */); ``` ```js -promiseWorker.register(function (message) { +promiseWorker.register(function(message) { console.log(message); // { hello: 'world', answer: 42, 'this is fun': true } }); ``` @@ -85,9 +91,9 @@ promiseWorker.register(function (message) { The registered handler can return either a Promise or a normal value: ```js -promiseWorker.register(function () { - return Promise.resolve().then(function () { - return 'much async, very promise'; +promiseWorker.register(function() { + return Promise.resolve().then(function() { + return "much async, very promise"; }); }); ``` @@ -103,24 +109,24 @@ promiseWorker.postMessage(null).then(function (message) { Any thrown errors or asynchronous rejections during a response will be propagated as a rejected promise. For instance: ```js -promiseWorker.register(function (message) { - throw new Error('naughty!'); +promiseWorker.register(function(message) { + throw new Error("naughty!"); }); ``` ```js -promiseWorker.postMessage('whoops').catch(function (err) { +promiseWorker.postMessage("whoops").catch(function(err) { console.log(err.message); // 'naughty!' }); ``` -But what about errors in the worker that are *not* during a response? (Errors in the host, you can handle as you would normally do.) +But what about errors in the worker that are _not_ during a response? (Errors in the host, you can handle as you would normally do.) For a Web Worker, we could just use [the normal `error` event](https://developer.mozilla.org/en-US/docs/Web/API/AbstractWorker/onerror) and be fine. But for a Shared Worker, that is not the case, because browsers seem to handle errors inside Shared Workers differently (currently Firefox seems to send the normal `error` event to all hosts, but [Chrome does not](https://bugs.chromium.org/p/chromium/issues/detail?id=105001)). Therefore, promise-worker-bi includes a unified API that works in Web Workers and Shared Workers. ```js -promiseWorker.registerError(function (err) { - console.log('Error inside worker!', err); +promiseWorker.registerError(function(err) { + console.log("Error inside worker!", err); }); ``` @@ -135,21 +141,25 @@ If you use a source map for your worker script, this will not be reflected in th If you need to send messages of multiple types to the worker, just add some type information to the message you send: ```js -promiseWorker.postMessage({ - type: 'en' -}).then(/* ... */); +promiseWorker + .postMessage({ + type: "en" + }) + .then(/* ... */); -promiseWorker.postMessage({ - type: 'fr' -}).then(/* ... */); +promiseWorker + .postMessage({ + type: "fr" + }) + .then(/* ... */); ``` ```js -promiseWorker.register(function (message) { - if (message.type === 'en') { - return 'Hello!'; - } else if (message.type === 'fr') { - return 'Bonjour!'; +promiseWorker.register(function(message) { + if (message.type === "en") { + return "Hello!"; + } else if (message.type === "fr") { + return "Bonjour!"; } }); ``` @@ -162,60 +172,59 @@ Here's an example: ```js // main.js -var PromiseWorker = require('promise-worker-bi'); +import { PWBHost } from "promise-worker-bi"; -var worker = new SharedWorker('worker.js'); -var promiseWorker = new PromiseWorker(worker); +var worker = new SharedWorker("worker.js"); +var promiseWorker = new PWBHost(worker); -promiseWorker.register(function (message) { +promiseWorker.register(function(message) { console.log(message); }); // setTimeout is just to give you enough time to open main.js and main2.js in // two separate tabs. -setTimeout(function () { - promiseWorker.postMessage('broadcast').then(function (response) { - console.log('Echoed response:', response); - }) +setTimeout(function() { + promiseWorker.postMessage("broadcast").then(function(response) { + console.log("Echoed response:", response); + }); }, 1000); ``` ```js // main2.js -var PromiseWorker = require('promise-worker-bi'); +import { PWBHost } from "promise-worker-bi"; -var worker = new SharedWorker('worker.js'); -var promiseWorker = new PromiseWorker(worker); +var worker = new SharedWorker("worker.js"); +var promiseWorker = new PWBHost(worker); -promiseWorker.register(function (message) { +promiseWorker.register(function(message) { console.log(message); }); // setTimeout is just to give you enough time to open main.js and main2.js in // two separate tabs. -setTimeout(function () { - promiseWorker.postMessage('just this tab').then(function (response) { - console.log('Echoed response:', response); - }) +setTimeout(function() { + promiseWorker.postMessage("just this tab").then(function(response) { + console.log("Echoed response:", response); + }); }, 2000); ``` ```js // worker.js -var PromiseWorker = require('promise-worker-bi'); +import { PWBWorker } from "promise-worker-bi"; -var promiseWorker = new PromiseWorker(); +var promiseWorker = new PWBWorker(); -promiseWorker.register(function (message, hostID) { - if (message === 'broadcast') { - promiseWorker.postMessage('to all tabs'); +promiseWorker.register(function(message, hostID) { + if (message === "broadcast") { + promiseWorker.postMessage("to all tabs"); } else { - promiseWorker.postMessage('hello host ' + hostID, hostID); + promiseWorker.postMessage("hello host " + hostID, hostID); } return message; }); - ``` Then open main.js and main2.js in two browser tabs. The message sent from main.js ('broadcast') will result in worker.js sending a message to both tabs, but the message sent in main2.js will result in a message sent only to that one tab. So if you look in the consoles in your two tabs, you will see this in the first tab: @@ -231,37 +240,43 @@ And this in the second tab: (If you open main2.js first, "hello host 1" will instead be "hello host 0".) -Browser support ----- +## Browser support -* Chrome -* Firefox -* Safari 8+ -* IE 10+ -* Edge -* iOS 8+ -* Android 4.4+ +- Chrome +- Firefox +- Safari 8+ +- IE 10+ +- Edge +- iOS 8+ +- Android 4.4+ Old browsers will need Map and Promise polyfills. There used to be automated tests in various browsers via [zuul](https://github.com/defunctzombie/zuul) and Sauce Labs, but it suffered bit rot and I could no longer get it to work consistently (PRs welcome!). Currently, `yarn test` uses [Karma](https://karma-runner.github.io/) to run tests in whatever versions of Chrome and Firefox you have installed. -API ---- +## API ### Main bundle -#### `new PromiseWorker(worker: Worker | SharedWorker)` +#### `new PWBHost(worker: Worker | SharedWorker)` -Create a new instance of `PromiseWorker`, using the given worker. +Create a new instance of `PWBHost`, using the given worker. -* `worker` - the `Worker`, `SharedWorker` or [PseudoWorker](https://github.com/nolanlawson/pseudo-worker) to use. +- `worker` - the `Worker`, `SharedWorker` or [PseudoWorker](https://github.com/nolanlawson/pseudo-worker) to use. + +#### `promiseWorker.registerError((error: Error) => void)` + +This should only be called in the browser, not in a worker. + +When an error in your web/shared worker process occurs that is _not_ directly in response to a `promiseWorker.postMessage` call, it will be sent to the callback you provide here to `promiseWorker.registerError`. + +Although [normally stack traces are not sent from the worker to the main thread](https://github.com/mknichel/javascript-errors/blob/master/README.md#dedicated-workers), promise-worker-bi magically works around this problem so you will see a stack trace in `error`. ### Worker bundle -#### `new PromiseWorker()` +#### `new PWBWorker()` -Create a new instance of `PromiseWorker`. +Create a new instance of `PWBWorker`. ### Both bundles @@ -276,11 +291,3 @@ The `hostID` parameter is only defined inside a shared worker, in which case it Send a message to the browser or worker and return a Promise. The `hostID` parameter is only meaningful when sending a message from a shared worker. If you leave it out, it will send the message to all hosts. If you include it, it will send the message only to that specific host. You can get the `hostID` from the `promiseWorker.register` function described above. - -#### `promiseWorker.registerError((error: Error) => void)` - -This should only be called in the browser, not in a worker. - -When an error in your web/shared worker process occurs that is *not* directly in response to a `promiseWorker.postMessage` call, it will be sent to the callback you provide here to `promiseWorker.registerError`. - -Although [normally stack traces are not sent from the worker to the main thread](https://github.com/mknichel/javascript-errors/blob/master/README.md#dedicated-workers), promise-worker-bi magically works around this problem so you will see a stack trace in `error`. diff --git a/TODO b/TODO deleted file mode 100644 index 61e5343..0000000 --- a/TODO +++ /dev/null @@ -1,4 +0,0 @@ -Confirm tree shaking works in BBGM, including unused functions (not just exported class) -Confirm old browsers work in BBGM -update README -changelog