summaryrefslogtreecommitdiff
path: root/doc/api
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2017-09-01 17:03:41 +0200
committerAnna Henningsen <anna@addaleax.net>2018-06-06 19:43:52 +0200
commit0df031acadcc6490379d72676203a980c8d60592 (patch)
tree3f49864e72b0193ea9af937874f62c6316877ec4 /doc/api
parent8939f36630bd718fc0b0b8557cf7f2ed9ecab312 (diff)
downloadandroid-node-v8-0df031acadcc6490379d72676203a980c8d60592.tar.gz
android-node-v8-0df031acadcc6490379d72676203a980c8d60592.tar.bz2
android-node-v8-0df031acadcc6490379d72676203a980c8d60592.zip
worker: initial implementation
Implement multi-threading support for most of the API. Thanks to Stephen Belanger for reviewing this change in its original form, to Olivia Hugger for reviewing the documentation and some of the tests coming along with it, and to Alexey Orlenko and Timothy Gu for reviewing other parts of the tests. Refs: https://github.com/ayojs/ayo/pull/110 Refs: https://github.com/ayojs/ayo/pull/114 Refs: https://github.com/ayojs/ayo/pull/117 PR-URL: https://github.com/nodejs/node/pull/20876 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Shingo Inoue <leko.noor@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
Diffstat (limited to 'doc/api')
-rw-r--r--doc/api/errors.md23
-rw-r--r--doc/api/process.md27
-rw-r--r--doc/api/vm.md2
-rw-r--r--doc/api/worker.md299
4 files changed, 348 insertions, 3 deletions
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 0a49757da3..972d0971c4 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1313,6 +1313,13 @@ but not provided in the `transferList` for that call.
An [ES6 module][] could not be resolved.
+<a id="ERR_MISSING_PLATFORM_FOR_WORKER"></a>
+### ERR_MISSING_PLATFORM_FOR_WORKER
+
+The V8 platform used by this instance of Node.js does not support creating
+Workers. This is caused by lack of embedder support for Workers. In particular,
+this error will not occur with standard builds of Node.js.
+
<a id="ERR_MODULE_RESOLUTION_LEGACY"></a>
### ERR_MODULE_RESOLUTION_LEGACY
@@ -1722,6 +1729,22 @@ The fulfilled value of a linking promise is not a `vm.Module` object.
The current module's status does not allow for this operation. The specific
meaning of the error depends on the specific function.
+<a id="ERR_WORKER_NEED_ABSOLUTE_PATH"></a>
+### ERR_WORKER_NEED_ABSOLUTE_PATH
+
+The path for the main script of a worker is not an absolute path.
+
+<a id="ERR_WORKER_UNSERIALIZABLE_ERROR"></a>
+### ERR_WORKER_UNSERIALIZABLE_ERROR
+
+All attempts at serializing an uncaught exception from a worker thread failed.
+
+<a id="ERR_WORKER_UNSUPPORTED_EXTENSION"></a>
+### ERR_WORKER_UNSUPPORTED_EXTENSION
+
+The pathname used for the main script of a worker has an
+unknown file extension.
+
<a id="ERR_ZLIB_INITIALIZATION_FAILED"></a>
### ERR_ZLIB_INITIALIZATION_FAILED
diff --git a/doc/api/process.md b/doc/api/process.md
index 8205efbd78..0a9c52a44c 100644
--- a/doc/api/process.md
+++ b/doc/api/process.md
@@ -410,6 +410,8 @@ added: v0.7.0
The `process.abort()` method causes the Node.js process to exit immediately and
generate a core file.
+This feature is not available in [`Worker`][] threads.
+
## process.arch
<!-- YAML
added: v0.5.0
@@ -517,6 +519,8 @@ try {
}
```
+This feature is not available in [`Worker`][] threads.
+
## process.config
<!-- YAML
added: v0.7.7
@@ -918,6 +922,8 @@ console.log(process.env.test);
// => 1
```
+`process.env` is read-only in [`Worker`][] threads.
+
## process.execArgv
<!-- YAML
added: v0.7.7
@@ -1030,6 +1036,9 @@ If it is necessary to terminate the Node.js process due to an error condition,
throwing an *uncaught* error and allowing the process to terminate accordingly
is safer than calling `process.exit()`.
+In [`Worker`][] threads, this function stops the current thread rather
+than the current process.
+
## process.exitCode
<!-- YAML
added: v0.11.8
@@ -1203,6 +1212,7 @@ console.log(process.getgroups()); // [ 27, 30, 46, 1000 ]
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.kill(pid[, signal])
<!-- YAML
@@ -1306,6 +1316,9 @@ The _heap_ is where objects, strings, and closures are stored. Variables are
stored in the _stack_ and the actual JavaScript code resides in the
_code segment_.
+When using [`Worker`][] threads, `rss` will be a value that is valid for the
+entire process, while the other fields will only refer to the current thread.
+
## process.nextTick(callback[, ...args])
<!-- YAML
added: v0.1.26
@@ -1569,6 +1582,7 @@ if (process.getegid && process.setegid) {
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.seteuid(id)
<!-- YAML
@@ -1596,6 +1610,7 @@ if (process.geteuid && process.seteuid) {
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.setgid(id)
<!-- YAML
@@ -1623,6 +1638,7 @@ if (process.getgid && process.setgid) {
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.setgroups(groups)
<!-- YAML
@@ -1639,6 +1655,7 @@ The `groups` array can contain numeric group IDs, group names or both.
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.setuid(id)
<!-- YAML
@@ -1664,6 +1681,7 @@ if (process.getuid && process.setuid) {
This function is only available on POSIX platforms (i.e. not Windows or
Android).
+This feature is not available in [`Worker`][] threads.
## process.setUncaughtExceptionCaptureCallback(fn)
<!-- YAML
@@ -1700,6 +1718,8 @@ a [Writable][] stream.
`process.stderr` differs from other Node.js streams in important ways, see
[note on process I/O][] for more information.
+This feature is not available in [`Worker`][] threads.
+
## process.stdin
* {Stream}
@@ -1732,6 +1752,8 @@ In "old" streams mode the `stdin` stream is paused by default, so one
must call `process.stdin.resume()` to read from it. Note also that calling
`process.stdin.resume()` itself would switch stream to "old" mode.
+This feature is not available in [`Worker`][] threads.
+
## process.stdout
* {Stream}
@@ -1750,6 +1772,8 @@ process.stdin.pipe(process.stdout);
`process.stdout` differs from other Node.js streams in important ways, see
[note on process I/O][] for more information.
+This feature is not available in [`Worker`][] threads.
+
### A note on process I/O
`process.stdout` and `process.stderr` differ from other Node.js streams in
@@ -1865,6 +1889,8 @@ console.log(
);
```
+This feature is not available in [`Worker`][] threads.
+
## process.uptime()
<!-- YAML
added: v0.5.0
@@ -1992,6 +2018,7 @@ cases:
[`ChildProcess`]: child_process.html#child_process_class_childprocess
[`Error`]: errors.html#errors_class_error
[`EventEmitter`]: events.html#events_class_eventemitter
+[`Worker`]: worker.html#worker_worker
[`console.error()`]: console.html#console_console_error_data_args
[`console.log()`]: console.html#console_console_log_data_args
[`domain`]: domain.html
diff --git a/doc/api/vm.md b/doc/api/vm.md
index ff2f8c4ad0..f3b79199c1 100644
--- a/doc/api/vm.md
+++ b/doc/api/vm.md
@@ -174,7 +174,7 @@ const contextifiedSandbox = vm.createContext({ secret: 42 });
Creates a new ES `Module` object.
-*Note*: Properties assigned to the `import.meta` object that are objects may
+Properties assigned to the `import.meta` object that are objects may
allow the `Module` to access information outside the specified `context`, if the
object is created in the top level context. Use `vm.runInContext()` to create
objects in a specific context.
diff --git a/doc/api/worker.md b/doc/api/worker.md
index 974ff2e467..3517a4c86a 100644
--- a/doc/api/worker.md
+++ b/doc/api/worker.md
@@ -4,6 +4,94 @@
> Stability: 1 - Experimental
+The `worker` module provides a way to create multiple environments running
+on independent threads, and to create message channels between them. It
+can be accessed using:
+
+```js
+const worker = require('worker');
+```
+
+Workers are useful for performing CPU-intensive JavaScript operations; do not
+use them for I/O, since Node.js’s built-in mechanisms for performing operations
+asynchronously already treat it more efficiently than Worker threads can.
+
+Workers, unlike child processes or when using the `cluster` module, can also
+share memory efficiently by transferring `ArrayBuffer` instances or sharing
+`SharedArrayBuffer` instances between them.
+
+## Example
+
+```js
+const { Worker, isMainThread, parentPort, workerData } = require('worker');
+
+if (isMainThread) {
+ module.exports = async function parseJSAsync(script) {
+ return new Promise((resolve, reject) => {
+ const worker = new Worker(__filename, {
+ workerData: script
+ });
+ worker.on('message', resolve);
+ worker.on('error', reject);
+ worker.on('exit', (code) => {
+ if (code !== 0)
+ reject(new Error(`Worker stopped with exit code ${code}`));
+ });
+ });
+ };
+} else {
+ const { parse } = require('some-js-parsing-library');
+ const script = workerData;
+ parentPort.postMessage(parse(script));
+}
+```
+
+Note that this example spawns a Worker thread for each `parse` call.
+In practice, it is strongly recommended to use a pool of Workers for these
+kinds of tasks, since the overhead of creating Workers would likely exceed the
+benefit of handing the work off to it.
+
+## worker.isMainThread
+<!-- YAML
+added: REPLACEME
+-->
+
+* {boolean}
+
+Is `true` if this code is not running inside of a [`Worker`][] thread.
+
+## worker.parentPort
+<!-- YAML
+added: REPLACEME
+-->
+
+* {null|MessagePort}
+
+If this thread was spawned as a [`Worker`][], this will be a [`MessagePort`][]
+allowing communication with the parent thread. Messages sent using
+`parentPort.postMessage()` will be available in the parent thread
+using `worker.on('message')`, and messages sent from the parent thread
+using `worker.postMessage()` will be available in this thread using
+`parentPort.on('message')`.
+
+## worker.threadId
+<!-- YAML
+added: REPLACEME
+-->
+
+* {integer}
+
+An integer identifier for the current thread. On the corresponding worker object
+(if there is any), it is available as [`worker.threadId`][].
+
+## worker.workerData
+<!-- YAML
+added: REPLACEME
+-->
+
+An arbitrary JavaScript value that contains a clone of the data passed
+to this thread’s `Worker` constructor.
+
## Class: MessageChannel
<!-- YAML
added: REPLACEME
@@ -21,7 +109,7 @@ const { MessageChannel } = require('worker');
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });
-// prints: received { foo: 'bar' }
+// prints: received { foo: 'bar' } from the `port1.on('message')` listener
```
## Class: MessagePort
@@ -141,13 +229,220 @@ If listeners are attached or removed using `.on('message')`, the port will
be `ref()`ed and `unref()`ed automatically depending on whether
listeners for the event exist.
+## Class: Worker
+<!-- YAML
+added: REPLACEME
+-->
+
+The `Worker` class represents an independent JavaScript execution thread.
+Most Node.js APIs are available inside of it.
+
+Notable differences inside a Worker environment are:
+
+- The [`process.stdin`][], [`process.stdout`][] and [`process.stderr`][]
+ properties are set to `null`.
+- The [`require('worker').isMainThread`][] property is set to `false`.
+- The [`require('worker').parentPort`][] message port is available,
+- [`process.exit()`][] does not stop the whole program, just the single thread,
+ and [`process.abort()`][] is not available.
+- [`process.chdir()`][] and `process` methods that set group or user ids
+ are not available.
+- [`process.env`][] is a read-only reference to the environment variables.
+- [`process.title`][] cannot be modified.
+- Signals will not be delivered through [`process.on('...')`][Signals events].
+- Execution may stop at any point as a result of [`worker.terminate()`][]
+ being invoked.
+- IPC channels from parent processes are not accessible.
+
+Currently, the following differences also exist until they are addressed:
+
+- The [`inspector`][] module is not available yet.
+- Native addons are not supported yet.
+
+Creating `Worker` instances inside of other `Worker`s is possible.
+
+Like [Web Workers][] and the [`cluster` module][], two-way communication can be
+achieved through inter-thread message passing. Internally, a `Worker` has a
+built-in pair of [`MessagePort`][]s that are already associated with each other
+when the `Worker` is created. While the `MessagePort` object on the parent side
+is not directly exposed, its functionalities are exposed through
+[`worker.postMessage()`][] and the [`worker.on('message')`][] event
+on the `Worker` object for the parent thread.
+
+To create custom messaging channels (which is encouraged over using the default
+global channel because it facilitates separation of concerns), users can create
+a `MessageChannel` object on either thread and pass one of the
+`MessagePort`s on that `MessageChannel` to the other thread through a
+pre-existing channel, such as the global one.
+
+See [`port.postMessage()`][] for more information on how messages are passed,
+and what kind of JavaScript values can be successfully transported through
+the thread barrier.
+
+For example:
+
+```js
+const assert = require('assert');
+const { Worker, MessageChannel, MessagePort, isMainThread } = require('worker');
+if (isMainThread) {
+ const worker = new Worker(__filename);
+ const subChannel = new MessageChannel();
+ worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
+ subChannel.port2.on('message', (value) => {
+ console.log('received:', value);
+ });
+} else {
+ require('worker').once('workerMessage', (value) => {
+ assert(value.hereIsYourPort instanceof MessagePort);
+ value.hereIsYourPort.postMessage('the worker is sending this');
+ value.hereIsYourPort.close();
+ });
+}
+```
+
+### new Worker(filename, options)
+
+* `filename` {string} The absolute path to the Worker’s main script.
+ If `options.eval` is true, this is a string containing JavaScript code rather
+ than a path.
+* `options` {Object}
+ * `eval` {boolean} If true, interpret the first argument to the constructor
+ as a script that is executed once the worker is online.
+ * `data` {any} Any JavaScript value that will be cloned and made
+ available as [`require('worker').workerData`][]. The cloning will occur as
+ described in the [HTML structured clone algorithm][], and an error will be
+ thrown if the object cannot be cloned (e.g. because it contains
+ `function`s).
+
+### Event: 'error'
+<!-- YAML
+added: REPLACEME
+-->
+
+* `err` {Error}
+
+The `'error'` event is emitted if the worker thread throws an uncaught
+exception. In that case, the worker will be terminated.
+
+### Event: 'exit'
+<!-- YAML
+added: REPLACEME
+-->
+
+* `exitCode` {integer}
+
+The `'exit'` event is emitted once the worker has stopped. If the worker
+exited by calling [`process.exit()`][], the `exitCode` parameter will be the
+passed exit code. If the worker was terminated, the `exitCode` parameter will
+be `1`.
+
+### Event: 'message'
+<!-- YAML
+added: REPLACEME
+-->
+
+* `value` {any} The transmitted value
+
+The `'message'` event is emitted when the worker thread has invoked
+[`require('worker').postMessage()`][]. See the [`port.on('message')`][] event
+for more details.
+
+### Event: 'online'
+<!-- YAML
+added: REPLACEME
+-->
+
+The `'online'` event is emitted when the worker thread has started executing
+JavaScript code.
+
+### worker.postMessage(value[, transferList])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `value` {any}
+* `transferList` {Object[]}
+
+Send a message to the worker that will be received via
+[`require('worker').on('workerMessage')`][]. See [`port.postMessage()`][] for
+more details.
+
+### worker.ref()
+<!-- YAML
+added: REPLACEME
+-->
+
+Opposite of `unref()`, calling `ref()` on a previously `unref()`ed worker will
+*not* let the program exit if it's the only active handle left (the default
+behavior). If the worker is `ref()`ed, calling `ref()` again will have
+no effect.
+
+### worker.terminate([callback])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `callback` {Function}
+
+Stop all JavaScript execution in the worker thread as soon as possible.
+`callback` is an optional function that is invoked once this operation is known
+to have completed.
+
+**Warning**: Currently, not all code in the internals of Node.js is prepared to
+expect termination at arbitrary points in time and may crash if it encounters
+that condition. Consequently, you should currently only call `.terminate()` if
+it is known that the Worker thread is not accessing Node.js core modules other
+than what is exposed in the `worker` module.
+
+### worker.threadId
+<!-- YAML
+added: REPLACEME
+-->
+
+* {integer}
+
+An integer identifier for the referenced thread. Inside the worker thread,
+it is available as [`require('worker').threadId`][].
+
+### worker.unref()
+<!-- YAML
+added: REPLACEME
+-->
+
+Calling `unref()` on a worker will allow the thread to exit if this is the only
+active handle in the event system. If the worker is already `unref()`ed calling
+`unref()` again will have no effect.
+
[`Buffer`]: buffer.html
-[child processes]: child_process.html
[`EventEmitter`]: events.html
[`MessagePort`]: #worker_class_messageport
[`port.postMessage()`]: #worker_port_postmessage_value_transferlist
+[`Worker`]: #worker_class_worker
+[`worker.terminate()`]: #worker_worker_terminate_callback
+[`worker.postMessage()`]: #worker_worker_postmessage_value_transferlist_1
+[`worker.on('message')`]: #worker_event_message_1
+[`worker.threadId`]: #worker_worker_threadid_1
+[`port.on('message')`]: #worker_event_message
+[`process.exit()`]: process.html#process_process_exit_code
+[`process.abort()`]: process.html#process_process_abort
+[`process.chdir()`]: process.html#process_process_chdir_directory
+[`process.env`]: process.html#process_process_env
+[`process.stdin`]: process.html#process_process_stdin
+[`process.stderr`]: process.html#process_process_stderr
+[`process.stdout`]: process.html#process_process_stdout
+[`process.title`]: process.html#process_process_title
+[`require('worker').workerData`]: #worker_worker_workerdata
+[`require('worker').on('workerMessage')`]: #worker_event_workermessage
+[`require('worker').postMessage()`]: #worker_worker_postmessage_value_transferlist
+[`require('worker').isMainThread`]: #worker_worker_ismainthread
+[`require('worker').threadId`]: #worker_worker_threadid
+[`cluster` module]: cluster.html
+[`inspector`]: inspector.html
[v8.serdes]: v8.html#v8_serialization_api
[`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
+[Signals events]: process.html#process_signal_events
[`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
[browser `MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
+[child processes]: child_process.html
[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
+[Web Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API