Node.js v12.13.1 文档


worker_threads(工作线程)#

中英对照提交修改

稳定性: 2 - 稳定

worker_threads 模块允许使用并行地执行 JavaScript 的线程。 要访问它:

const worker = require('worker_threads');

工作线程对于执行 CPU 密集型的 JavaScript 操作非常有用。 它们在 I/O 密集型的工作中用途不大。 Node.js 的内置的异步 I/O 操作比工作线程效率更高。

child_processcluster 不同, worker_threads 可以共享内存。 它们通过传输 ArrayBuffer 实例或共享 SharedArrayBuffer 实例来实现。

const {
  Worker, isMainThread, parentPort, workerData
} = require('worker_threads');

if (isMainThread) {
  module.exports = 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(`工作线程使用退出码 ${code} 停止`));
      });
    });
  };
} else {
  const { parse } = require('一些 js 解析库');
  const script = workerData;
  parentPort.postMessage(parse(script));
}

上面的示例为每个 parse() 调用衍生一个工作线程。 在实际的实践中,应使用工作线程池代替这些任务。 否则,创建工作线程的开销可能会超出其收益。

当实现工作线程池时,可使用 AsyncResource API 来通知诊断的工具(例如为了提供异步的堆栈跟踪)有关任务及其结果之间的相关性。

worker.isMainThread#

中英对照提交修改

如果此代码不在 Worker 线程内运行,则为 true

const { Worker, isMainThread } = require('worker_threads');

if (isMainThread) {
  // 这会在工作线程实例中重新加载当前文件。
  new Worker(__filename);
} else {
  console.log('在工作线程中');
  console.log(isMainThread);  // 打印 'false'。
}

worker.moveMessagePortToContext(port, contextifiedSandbox)#

暂无中英对照提交修改

Transfer a MessagePort to a different vm Context. The original port object will be rendered unusable, and the returned MessagePort instance will take its place.

The returned MessagePort will be an object in the target context, and will inherit from its global Object class. Objects passed to the port.onmessage() listener will also be created in the target context and inherit from its global Object class.

However, the created MessagePort will no longer inherit from EventEmitter, and only port.onmessage() can be used to receive events using it.

worker.parentPort#

暂无中英对照提交修改

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').

const { Worker, isMainThread, parentPort } = require('worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename);
  worker.once('message', (message) => {
    console.log(message);  // Prints 'Hello, world!'.
  });
  worker.postMessage('Hello, world!');
} else {
  // When a message from the parent thread is received, send it back:
  parentPort.once('message', (message) => {
    parentPort.postMessage(message);
  });
}

worker.receiveMessageOnPort(port)#

暂无中英对照提交修改

Receive a single message from a given MessagePort. If no message is available, undefined is returned, otherwise an object with a single message property that contains the message payload, corresponding to the oldest message in the MessagePort’s queue.

const { MessageChannel, receiveMessageOnPort } = require('worker_threads');
const { port1, port2 } = new MessageChannel();
port1.postMessage({ hello: 'world' });

console.log(receiveMessageOnPort(port2));
// Prints: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// Prints: undefined

When this function is used, no 'message' event will be emitted and the onmessage listener will not be invoked.

worker.SHARE_ENV#

暂无中英对照提交修改

A special value that can be passed as the env option of the Worker constructor, to indicate that the current thread and the Worker thread should share read and write access to the same set of environment variables.

const { Worker, SHARE_ENV } = require('worker_threads');
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
  .on('exit', () => {
    console.log(process.env.SET_IN_WORKER);  // Prints 'foo'.
  });

worker.threadId#

暂无中英对照提交修改

An integer identifier for the current thread. On the corresponding worker object (if there is any), it is available as worker.threadId. This value is unique for each Worker instance inside a single process.

worker.workerData#

暂无中英对照提交修改

An arbitrary JavaScript value that contains a clone of the data passed to this thread’s Worker constructor.

The data is cloned as if using postMessage(), according to the HTML structured clone algorithm.

const { Worker, isMainThread, workerData } = require('worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hello, world!' });
} else {
  console.log(workerData);  // Prints 'Hello, world!'.
}

MessageChannel 类#

暂无中英对照提交修改

Instances of the worker.MessageChannel class represent an asynchronous, two-way communications channel. The MessageChannel has no methods of its own. new MessageChannel() yields an object with port1 and port2 properties, which refer to linked MessagePort instances.

const { MessageChannel } = require('worker_threads');

const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });
// Prints: received { foo: 'bar' } from the `port1.on('message')` listener

MessagePort 类#

暂无中英对照提交修改

Instances of the worker.MessagePort class represent one end of an asynchronous, two-way communications channel. It can be used to transfer structured data, memory regions and other MessagePorts between different Workers.

With the exception of MessagePorts being EventEmitters rather than EventTargets, this implementation matches browser MessagePorts.

'close' 事件#

暂无中英对照提交修改

The 'close' event is emitted once either side of the channel has been disconnected.

const { MessageChannel } = require('worker_threads');
const { port1, port2 } = new MessageChannel();

// Prints:
//   foobar
//   closed!
port2.on('message', (message) => console.log(message));
port2.on('close', () => console.log('closed!'));

port1.postMessage('foobar');
port1.close();

'message' 事件#

暂无中英对照提交修改

  • value <any> The transmitted value

The 'message' event is emitted for any incoming message, containing the cloned input of port.postMessage().

Listeners on this event will receive a clone of the value parameter as passed to postMessage() and no further arguments.

port.close()#

暂无中英对照提交修改

Disables further sending of messages on either side of the connection. This method can be called when no further communication will happen over this MessagePort.

The 'close' event will be emitted on both MessagePort instances that are part of the channel.

port.postMessage(value[, transferList])#

暂无中英对照提交修改

Sends a JavaScript value to the receiving side of this channel. value will be transferred in a way which is compatible with the HTML structured clone algorithm.

In particular, the significant differences to JSON are:

  • value may contain circular references.
  • value may contain instances of builtin JS types such as RegExps, BigInts, Maps, Sets, etc.
  • value may contain typed arrays, both using ArrayBuffers and SharedArrayBuffers.
  • value may contain WebAssembly.Module instances.
  • value may not contain native (C++-backed) objects other than MessagePorts.
const { MessageChannel } = require('worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const circularData = {};
circularData.foo = circularData;
// Prints: { foo: [Circular] }
port2.postMessage(circularData);

transferList may be a list of ArrayBuffer and MessagePort objects. After transferring, they will not be usable on the sending side of the channel anymore (even if they are not contained in value). Unlike with child processes, transferring handles such as network sockets is currently not supported.

If value contains SharedArrayBuffer instances, those will be accessible from either thread. They cannot be listed in transferList.

value may still contain ArrayBuffer instances that are not in transferList; in that case, the underlying memory is copied rather than moved.

const { MessageChannel } = require('worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const uint8Array = new Uint8Array([ 1, 2, 3, 4 ]);
// This posts a copy of `uint8Array`:
port2.postMessage(uint8Array);
// This does not copy data, but renders `uint8Array` unusable:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);

// The memory for the `sharedUint8Array` will be accessible from both the
// original and the copy received by `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);

// This transfers a freshly created message port to the receiver.
// This can be used, for example, to create communication channels between
// multiple `Worker` threads that are children of the same parent thread.
const otherChannel = new MessageChannel();
port2.postMessage({ port: otherChannel.port1 }, [ otherChannel.port1 ]);

Because the object cloning uses the structured clone algorithm, non-enumerable properties, property accessors, and object prototypes are not preserved. In particular, Buffer objects will be read as plain Uint8Arrays on the receiving side.

The message object will be cloned immediately, and can be modified after posting without having side effects.

For more information on the serialization and deserialization mechanisms behind this API, see the serialization API of the v8 module.

port.ref()#

暂无中英对照提交修改

Opposite of unref(). Calling ref() on a previously unref()ed port will not let the program exit if it's the only active handle left (the default behavior). If the port is ref()ed, calling ref() again will have no effect.

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.

port.start()#

暂无中英对照提交修改

Starts receiving messages on this MessagePort. When using this port as an event emitter, this will be called automatically once 'message' listeners are attached.

This method exists for parity with the Web MessagePort API. In Node.js, it is only useful for ignoring messages when no event listener is present. Node.js also diverges in its handling of .onmessage. Setting it will automatically call .start(), but unsetting it will let messages queue up until a new handler is set or the port is discarded.

port.unref()#

暂无中英对照提交修改

Calling unref() on a port will allow the thread to exit if this is the only active handle in the event system. If the port is already unref()ed calling unref() again will have no effect.

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.

Worker 类#

中英对照提交修改

Worker 类代表一个独立的 JavaScript 执行线程。 大多数 Node.js API 都在其中可用。

工作线程环境中的显着差异是:

可以在其他 Worker 实例中创建 Worker 实例。

Web 工作线程cluster 模块一样,可以通过线程间的消息传递来实现双向通信。 在内部,一个 Worker 具有一对内置的 MessagePort,在创建该 Worker 时它们已经相互关联。 虽然父端的 MessagePort 对象没有直接公开,但其功能是通过父线程的 Worker 对象上的 worker.postMessage()worker.on('message') 事件公开的。

要创建自定义的消息传递通道(建议使用默认的全局通道,因为这样可以促进关联点的分离),用户可以在任一线程上创建一个 MessageChannel 对象,并将该 MessageChannel 上的 MessagePort 中的一个通过预先存在的通道传给另一个线程,例如全局的通道。

有关如何传递消息以及可以通过线程屏障成功地传输哪类 JavaScript 值的更多信息,请参阅 port.postMessage()

const assert = require('assert');
const {
  Worker, MessageChannel, MessagePort, isMainThread, parentPort
} = require('worker_threads');
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('接收到:', value);
  });
} else {
  parentPort.once('message', (value) => {
    assert(value.hereIsYourPort instanceof MessagePort);
    value.hereIsYourPort.postMessage('工作线程正在发送此消息');
    value.hereIsYourPort.close();
  });
}

new Worker(filename[, options])#

中英对照提交修改

  • filename <string> 工作线程主脚本的路径。必须是以 ./../ 开头的绝对路径或相对路径(即相对于当前工作目录)。 如果 options.evaltrue,则这是一个包含 JavaScript 代码而不是路径的字符串。
  • options <Object>

    • env <Object> 如果设置,则指定工作线程中 process.env 的初始值。 作为一个特殊值,worker.SHARE_ENV 可以用于指定父线程和子线程应该共享它们的环境变量。 在这种情况下,对一个线程的 process.env 对象的更改也会影响另一个线程。 默认值: process.env
    • eval <boolean> 如果为 true,则将构造函数的第一个参数解释为工作线程联机后执行的脚本。
    • execArgv <string[]> 传递给工作线程的 node CLI 选项的列表。 不支持 V8 选项(例如 --max-old-space-size)和影响进程的选项(例如 --title)。 如果设置,则它将会作为工作线程内部的 process.execArgv 提供。 默认情况下,选项将会从父线程继承。
    • stdin <boolean> 如果将其设置为 true,则 worker.stdin 将会提供一个可写流,其内容将会在工作线程中以 process.stdin 出现。 默认情况下,不提供任何数据。
    • stdout <boolean> 如果将其设置为 true,则 worker.stdout 将不会自动地通过管道传递到父线程中的 process.stdout
    • stderr <boolean> 如果将其设置为 true,则 worker.stderr 将不会自动地通过管道传递到父线程中的 process.stderr
    • workerData <any> 能被克隆并作为 require('worker_threads').workerData 的任何 JavaScript 值。 克隆将会按照 HTML 结构化克隆算法中描述的进行,如果对象无法被克隆(例如,因为它包含 function),则会抛出错误。

'error' 事件#

暂无中英对照提交修改

The 'error' event is emitted if the worker thread throws an uncaught exception. In that case, the worker will be terminated.

'exit' 事件#

暂无中英对照提交修改

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.

'message' 事件#

暂无中英对照提交修改

  • value <any> The transmitted value

The 'message' event is emitted when the worker thread has invoked require('worker_threads').parentPort.postMessage(). See the port.on('message') event for more details.

'online' 事件#

暂无中英对照提交修改

The 'online' event is emitted when the worker thread has started executing JavaScript code.

worker.postMessage(value[, transferList])#

暂无中英对照提交修改

Send a message to the worker that will be received via require('worker_threads').parentPort.on('message'). See port.postMessage() for more details.

worker.ref()#

暂无中英对照提交修改

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.stderr#

暂无中英对照提交修改

This is a readable stream which contains data written to process.stderr inside the worker thread. If stderr: true was not passed to the Worker constructor, then data will be piped to the parent thread's process.stderr stream.

worker.stdin#

暂无中英对照提交修改

If stdin: true was passed to the Worker constructor, this is a writable stream. The data written to this stream will be made available in the worker thread as process.stdin.

worker.stdout#

暂无中英对照提交修改

This is a readable stream which contains data written to process.stdout inside the worker thread. If stdout: true was not passed to the Worker constructor, then data will be piped to the parent thread's process.stdout stream.

worker.terminate()#

暂无中英对照提交修改

Stop all JavaScript execution in the worker thread as soon as possible. Returns a Promise for the exit code that is fulfilled when the 'exit' event is emitted.

worker.threadId#

暂无中英对照提交修改

An integer identifier for the referenced thread. Inside the worker thread, it is available as require('worker_threads').threadId. This value is unique for each Worker instance inside a single process.

worker.unref()#

暂无中英对照提交修改

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.