UNPKG

7.04 kBMarkdownView Raw
1<h1 align="center">
2 <img alt="threads.js" src="./docs/assets/logo-label.png" width="75%" />
3</h1>
4<p align="center">
5 <a href="https://travis-ci.org/andywer/threads.js" target="_blank"><img alt="Build status" src="https://img.shields.io/travis/andywer/threads.js/v1.svg?style=flat-square"></a>
6 <a href="https://www.npmjs.com/package/threads" target="_blank"><img alt="npm (tag)" src="https://img.shields.io/npm/v/threads.svg?style=flat-square"></a>
7 <a href="https://gitter.im/threadsjs/community" target="_blank"><img alt="Chat room" src="https://img.shields.io/badge/chat-gitter.im-orange" /></a>
8</p>
9
10<br />
11
12Offload CPU-intensive tasks to worker threads in node.js, web browsers and electron using one uniform API.
13
14Uses web workers in the browser, `worker_threads` in node 12+ and [`tiny-worker`](https://github.com/avoidwork/tiny-worker) in node 8 to 11.
15
16### Features
17
18* First-class support for **async functions** & **observables**
19* Write code once, run it **on all platforms**
20* Manage bulk task executions with **thread pools**
21* Use **require()** and **import**/**export** in workers
22* Works great with **webpack**
23
24### Version 0.x
25
26You can find the old version 0.12 of threads.js on the [`v0` branch](https://github.com/andywer/threads.js/tree/v0). All the content on this page refers to version 1.0 which is a rewrite of the library with a whole new API.
27
28## Installation
29
30```
31npm install threads tiny-worker
32```
33
34*You only need to install the `tiny-worker` package to support node.js < 12. It's an optional dependency and used as a fallback if `worker_threads` are not available.*
35
36## Platform support
37
38<details>
39<summary>Run on node.js</summary>
40
41<p></p>
42
43Running code using threads.js in node works out of the box.
44
45Note that we wrap the native `Worker`, so `new Worker("./foo/bar")` will resolve the path relative to the module that calls it, not relative to the current working directory.
46
47That aligns it with the behavior when bundling the code with webpack or parcel.
48
49</details>
50
51<details>
52<summary>Webpack build setup</summary>
53
54#### Webpack config
55
56Use with the [`threads-plugin`](https://github.com/andywer/threads-plugin). It will transparently detect all `new Worker("./unbundled-path")` expressions, bundles the worker code and replaces the `new Worker(...)` path with the worker bundle path, so you don't need to explicitly use the `worker-loader` or define extra entry points.
57
58```sh
59 npm install -D threads-plugin
60```
61
62Then add it to your `webpack.config.js`:
63
64```diff
65+ const ThreadsPlugin = require('threads-plugin');
66
67 module.exports = {
68 // ...
69 plugins: [
70+ new ThreadsPlugin()
71 ]
72 // ...
73 }
74```
75
76#### Node.js bundles
77
78If you are using webpack to create a bundle that will be run in node (webpack config `target: "node"`), you also need to specify that the `tiny-worker` package used for node < 12 should not be bundled:
79
80```diff
81 module.exports = {
82 // ...
83+ externals: {
84+ "tiny-worker": "tiny-worker"
85+ }
86 // ...
87}
88```
89
90Make sure that `tiny-worker` is listed in your `package.json` `dependencies` in that case.
91
92#### When using TypeScript
93
94Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.
95
96Make sure the TypeScript compiler keeps the `import` / `export` statements intact, so webpack resolves them. Otherwise the `threads-plugin` won't be able to do its job.
97
98```diff
99 module.exports = {
100 // ...
101 module: {
102 rules: [
103 {
104 test: /\.ts$/,
105 loader: "ts-loader",
106+ options: {
107+ compilerOptions: {
108+ module: "esnext"
109+ }
110+ }
111 }
112 ]
113 },
114 // ...
115 }
116```
117
118</details>
119
120<details>
121<summary>Parcel bundler setup</summary>
122
123<p></p>
124
125You need to import `threads/register` once at the beginning of your application code (in the master code, not in the workers):
126
127```diff
128 import { spawn } from "threads"
129+ import "threads/register"
130
131 // ...
132
133 const work = await spawn(new Worker("./worker"))
134```
135
136This registers the library's `Worker` implementation for your platform as the global `Worker`. This is necessary, since you cannot `import { Worker } from "threads"` or Parcel won't recognize `new Worker()` as a web worker anymore.
137
138Be aware that this might affect any code that tries to instantiate a normal web worker `Worker` and now instead instantiates a threads.js `Worker`. The threads.js `Worker` is just a web worker with some sugar on top, but that sugar might have unexpected side effects on third-party libraries.
139
140Everything else should work out of the box.
141
142</details>
143
144## Getting Started
145
146### Basics
147
148```js
149// master.js
150import { spawn, Thread, Worker } from "threads"
151
152const auth = await spawn(new Worker("./workers/auth"))
153const hashed = await auth.hashPassword("Super secret password", "1234")
154
155console.log("Hashed password:", hashed)
156
157await Thread.terminate(auth)
158```
159
160```js
161// workers/auth.js
162import sha256 from "js-sha256"
163import { expose } from "threads/worker"
164
165expose({
166 hashPassword(password, salt) {
167 return sha256(password + salt)
168 }
169})
170```
171
172### spawn()
173
174The `hashPassword()` function of the `auth` object in the master code proxies the call to the `hashPassword()` function in the worker:
175
176If the worker's function returns a promise or an observable then you can just use the return value as such in the master code. If the function returns a primitive value, expect the master function to return a promise resolving to that value.
177
178### expose()
179
180Use `expose()` to make a function or an object containing methods callable from the master thread.
181
182In case of exposing an object, `spawn()` will asynchronously return an object exposing all the object's functions. If you `expose()` a function, `spawn` will also return a callable function, not an object.
183
184## Usage
185
186<p>
187 Find the full documentation on the <a href="https://threads.js.org/" rel="nofollow">website</a>:
188</p>
189
190- [**Quick start**](https://threads.js.org/getting-started)
191- [**Basic usage**](https://threads.js.org/usage)
192- [**Using observables**](https://threads.js.org/usage-observables)
193- [**Thread pools**](https://threads.js.org/usage-pool)
194- [**Advanced**](https://threads.js.org/usage-advanced)
195
196## Webpack
197
198Threads.js works with webpack. Usually all you need to do is adding the
199[`threads-plugin`](https://github.com/andywer/threads-plugin).
200
201See [Build with webpack](https://threads.js.org/getting-started#build-with-webpack)
202on the website for details.
203
204<!--
205## API
206
207TODO
208-->
209
210## Debug
211
212We are using the [`debug`](https://github.com/visionmedia/debug) package to provide opt-in debug logging. All the package's debug messages have a scope starting with `threads:`, with different sub-scopes:
213
214- `threads:master:messages`
215- `threads:master:spawn`
216- `threads:master:thread-utils`
217- `threads:pool:${poolName || poolID}`
218
219Set it to `DEBUG=threads:*` to enable all the library's debug logging. To run its tests with full debug logging, for instance:
220
221```
222DEBUG=threads:* npm test
223```
224
225## License
226
227MIT