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 |
|
12 | Offload CPU-intensive tasks to worker threads in node.js, web browsers and electron using one uniform API.
|
13 |
|
14 | Uses 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 |
|
26 | You 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 | ```
|
31 | npm 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 |
|
43 | Running code using threads.js in node works out of the box.
|
44 |
|
45 | Note 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 |
|
47 | That 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 |
|
56 | Use 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 |
|
62 | Then 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 |
|
78 | If 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 |
|
90 | Make sure that `tiny-worker` is listed in your `package.json` `dependencies` in that case.
|
91 |
|
92 | #### When using TypeScript
|
93 |
|
94 | Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.
|
95 |
|
96 | Make 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 |
|
125 | You 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 |
|
136 | This 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 |
|
138 | Be 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 |
|
140 | Everything else should work out of the box.
|
141 |
|
142 | </details>
|
143 |
|
144 | ## Getting Started
|
145 |
|
146 | ### Basics
|
147 |
|
148 | ```js
|
149 | // master.js
|
150 | import { spawn, Thread, Worker } from "threads"
|
151 |
|
152 | const auth = await spawn(new Worker("./workers/auth"))
|
153 | const hashed = await auth.hashPassword("Super secret password", "1234")
|
154 |
|
155 | console.log("Hashed password:", hashed)
|
156 |
|
157 | await Thread.terminate(auth)
|
158 | ```
|
159 |
|
160 | ```js
|
161 | // workers/auth.js
|
162 | import sha256 from "js-sha256"
|
163 | import { expose } from "threads/worker"
|
164 |
|
165 | expose({
|
166 | hashPassword(password, salt) {
|
167 | return sha256(password + salt)
|
168 | }
|
169 | })
|
170 | ```
|
171 |
|
172 | ### spawn()
|
173 |
|
174 | The `hashPassword()` function of the `auth` object in the master code proxies the call to the `hashPassword()` function in the worker:
|
175 |
|
176 | If 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 |
|
180 | Use `expose()` to make a function or an object containing methods callable from the master thread.
|
181 |
|
182 | In 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 |
|
198 | Threads.js works with webpack. Usually all you need to do is adding the
|
199 | [`threads-plugin`](https://github.com/andywer/threads-plugin).
|
200 |
|
201 | See [Build with webpack](https://threads.js.org/getting-started#build-with-webpack)
|
202 | on the website for details.
|
203 |
|
204 |
|
205 | ## API
|
206 |
|
207 | TODO
|
208 | -->
|
209 |
|
210 | ## Debug
|
211 |
|
212 | We 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 |
|
219 | Set it to `DEBUG=threads:*` to enable all the library's debug logging. To run its tests with full debug logging, for instance:
|
220 |
|
221 | ```
|
222 | DEBUG=threads:* npm test
|
223 | ```
|
224 |
|
225 | ## License
|
226 |
|
227 | MIT
|