• Stars
    star
    225
  • Rank 171,397 (Top 4 %)
  • Language
    JavaScript
  • Created over 5 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A better way of working with web workers

web-worker-proxy

Build Status Code Coverage MIT License Version Bundle size (minified + gzip)

A better way of working with web workers. Uses JavaScript Proxies to make communcation with web workers similar to interacting with normal objects.

Why

Web workers are great to offload work to a different thread in browsers. However, the messaging based API is not very easy to work with. This library makes working with web workers similar to how you'd interact with a local object, thanks to the power of proxies.

Features

  • Access and set properties on the proxied object asynchronously, even nested ones
  • Call functions on the proxied object and receive the result asynchronously
  • Pass callbacks (limited functionality) to the worker which can be called asynchronously
  • Receive thrown errors without extra handling for serialization

Installation

npm install web-worker-proxy

or

yarn add web-worker-proxy

Usage

First, we need to wrap our worker:

// app.js
import { create } from 'web-worker-proxy';

const worker = create(new Worker('worker.js'));

Inside the web worker, we need to wrap the target object to proxy it:

// worker.js
import { proxy } from 'web-worker-proxy';

proxy({
  name: { first: 'John', last: 'Doe' },
  add: (a, b) => a + b,
});

Now we can access properties, call methods etc. by using the await keyword, or passing a callback to then:

console.log(await worker.name.first); // 'John'

// or

worker.name.first.then(result => {
  console.log(result); // 'John'
});

Accessing properties is lazy, so the actual operation doesn't start until you await the value or call then on it.

Supported operations

Accessing a property

You can access any serializable properties on the proxied object asynchronously:

// Serializable values
console.log(await worker.name);

// Nested properties
console.log(await worker.name.first);

// Even array indices
console.log(await worker.items[0]);

When accessing a property, you'll get a thenable (an object with a then method), not an normal promise. If you want to use it as a normal promise, wrap it in Promise.resolve:

// Now you can call `catch` on the promise
Promise.resolve(worker.name.first).catch(error => {
  console.log(error);
});

Adding or updating a property

You can add a new property on the proxied object, or create a new one. It can be a nested property too:

worker.thisisawesome = {};
worker.thisisawesome.stuff = 42;

Calling methods

You can call methods on the proxied object, and pass any serializable arguments to it. The method will return a promise which will resolve to the value returned in the worker. You can also catch errors thrown from it:

try {
  const result = await worker.add(2, 3);
} catch (e) {
  console.log(e);
}

The method on the proxied object can return any serializable value or a promise which returns a serializable value.

It's also possible to pass callbacks to methods, with some limitations:

  • The arguments to the callback function must be serializable
  • The callback functions are one-way, which means, you cannot return a value from a callback function
  • The callback functions must be direct arguments to the method, it cannot be nested inside an object
worker.methods.validate(result => {
  console.log(result);
});

To prevent memory leaks, callbacks are cleaned up as soon as they are called. Which means, if your callback is supposed to be called multiple times, it won't work. However, you can persist a callback function for as long as you want with the persist helper. Persisting a function keeps around the event listeners. You must call dispose once the function is no longer needed so that they can be cleaned up.

import { persist } from 'web-worker-proxy';

const callback = persist(result => {
  if (result.done) {
    callback.dispose();
  } else {
    console.log(result);
  }
});

worker.subscribe(callback);

API

create(worker: Worker)

Create a proxy object which wraps the worker and allows you to interact with the proxied object inside the worker. It can take any object which implements the postMessage interface and the event interface (addEventListener and removeListener).

proxy(object: Object, target?: Worker = self)

Proxy an object so it can be interacted with. The first argument is the object to proxy, and the second argument is an object which implements the postMessage interface and the event interface, it defaults to self. It returns an object with a dispose method to dispose the proxy.

There can be only one proxy active for a given target at a time. To proxy a different object, we first need to dispose the previous proxy first by using the disposed method.

persist(function: Function)

Wrap a function so it can be persisted when passed as a callback. Returns an object with a dispose method to dispose the persisted function.

Browser compatibility

The library expects the Proxy and WeakMap constructors to be available globally. If you are using a browser which doesn't support these features, make sure to load appropriate polyfills.

The following environments support these features natively: Google Chrome >= 49, Microsoft Edge >= 12, Mozilla Firefox >= 18, Opera >= 36, Safari >= 10, Node >= 6.0.0.

Limitations

  • Since workers run in a separate thread, all operations are asynchronous, and will return thenables
  • The transferred data needs to be serializable (error objects are handled automatically), most browsers implement the structured clone algorithm for transferring data
  • The transferred data is always copied, which means the references will be different, and any mutations won't be visible

How it works

The library leverages proxies to intercept actions such as property access, function call etc., and then the details of the actions are sent to the web worker via the messaging API. The proxied object in the web worker recieves and performs the action, then sends the results back via the messaging API. Every action contains a unique id to distinguish itself from other actions.

Alternatives

Contributing

While developing, you can run the example app and open the console to see your changes:

yarn example

Make sure your code passes the unit tests, Flow and ESLint. Run the following to verify:

yarn test
yarn flow
yarn lint

To fix formatting errors, run the following:

yarn lint -- --fix

More Repositories

1

react-native-tab-view

A cross-platform Tab View component for React Native
TypeScript
5,134
star
2

react-simple-code-editor

Simple no-frills code editor with syntax highlighting
TypeScript
1,103
star
3

quik

🚀 A quick way to prototype and build apps with React and Babel with zero-setup.
JavaScript
477
star
4

react-navigation-addons

Add-ons for React Navigation
JavaScript
282
star
5

PocketGear

A clean and simple Pokédex app for Pokémon GO
TypeScript
197
star
6

monaco-editor-boilerplate

A simple boilerplate for Monaco editor with React.
JavaScript
187
star
7

gtk-theme-config

A tool to configure GTK theme colors.
Vala
89
star
8

babel-test

An opinionated library to make testing babel plugins easier.
JavaScript
80
star
9

react-boilerplate

An simple webpack boilerplate for React projects.
JavaScript
61
star
10

react-navigation-native-modal

React Navigation integration for React Native's Modal component
TypeScript
60
star
11

babel-plugin-css-prop

Babel plugin to transpile `css` prop to a styled component. (Experimental)
JavaScript
55
star
12

babel-plugin-optional-require

Babel plugin to optionaly require modules
JavaScript
52
star
13

react-native-in-app-purchase

IAP for React Native
Java
49
star
14

eslint-config-satya164

An ESLint config with automatic overrides for common environments such as TypeScript, Jest etc.
JavaScript
49
star
15

jest-file-snapshot

Jest matcher to write snapshots to a separate file instead of the default snapshot file used by Jest
JavaScript
41
star
16

babel-plugin-object-styles-to-template

Babel plugin to transpile object styles to template literal
JavaScript
35
star
17

typescript-template

Template repository for TypeScript projects with Babel
JavaScript
32
star
18

use-latest-callback

TypeScript
28
star
19

gjs-helpers

GNOME JavaScript helpers for async tasks
JavaScript
26
star
20

react-native-image-chooser

A React Native module to show system Image chooser. Currently only supports Android.
Java
26
star
21

Evolve

Evolve is a simple and minimal light theme designed to be easy on the eyes.
CSS
24
star
22

github-transfer-issues

Bulk transfer GitHub issues with puppeteer
JavaScript
23
star
23

emoji-invaders

Simple Emoji Invaders game
JavaScript
14
star
24

animated-to-reanimated

Helper to convert an Animated value to Reanimated and vice-versa
Java
12
star
25

grrr

A small tool to generate gresource files
JavaScript
11
star
26

minimal.widget

A minimal widget for Ãœbersicht which displays a panel on top right and apps list on top left
JavaScript
11
star
27

pigment

Color information, conversion and manipulation library
JavaScript
9
star
28

react-canvas-renderer

Custom React renderer which renders to <canvas />
JavaScript
8
star
29

random-color

Show a random color on tap.
Objective-C
6
star
30

publish-monorepo-packages

Tool to make easier publish packages in monorepo to the registry.
TypeScript
6
star
31

react-native-share

Java
5
star
32

warn-once

Show a warning once
JavaScript
5
star
33

language-x

An all new programming language
JavaScript
4
star
34

snack-modules

JavaScript
4
star
35

meme-generator

Meme Generator app built with Expo
JavaScript
4
star
36

json2scss

Convert JSON config files to SCSS!
JavaScript
4
star
37

croma

JavaScript
4
star
38

reanimated-2-drawer

TypeScript
3
star
39

huematic

Generate color schemes based on algorithms
JavaScript
3
star
40

react-native-jsitestlibrary

Java
3
star
41

actions-playground

Playing with GitHub actions
3
star
42

git-hooks-scripts

Run custom scripts as Git hooks
JavaScript
3
star
43

turbo-module-example

Example for backward compatible Turbo module
Java
2
star
44

drop-shadows

Generate drop shadows
OCaml
2
star
45

webrtc-messaging

TypeScript
2
star
46

magnetic-field-meter

Detect Magnetic field using device's Magnetometer
JavaScript
2
star
47

simple-website-boilerplate

A simple website boilerplate with BrowserSync and Sass
HTML
2
star
48

remark-syntax-highlight

(WIP) Syntax highlight code blocks with a custom highlight function in remark
JavaScript
2
star
49

turtle-v2-example

Java
2
star
50

timezones

JavaScript
1
star
51

dotfiles

JavaScript
1
star
52

animated-helpers

Helpers for React Native's Animated API
TypeScript
1
star
53

node-app-tasks

The action allows to run any npm/yarn command or a task defined in package.json
Shell
1
star
54

keycode

Find keyCode of a key
HTML
1
star