worker;
要创建一个 worker,首先必须创建一个 Worker
类的实例。它的第一个参数提供了包含 worker 的代码的文件的路径;第二个参数提供了一个名为 workerData
的包含一个属性的对象。这是我们希望线程在开始运行时可以访问的数据。
请注意:不管你是用的是 JavaScript, 还是最终要转换为 JavaScript 的语言(例如,TypeScript),路径应该始终引用带有 .js
或 .mjs
扩展名的文件。
我还想指出为什么使用回调方法,而不是返回在触发 message
事件时将解决的 promise。这是因为 worker 可以发送许多 message
事件,而不是一个。
正如你在上面的例子中所看到的,线程间的通信是基于事件的,这意味着我们设置了 worker 在发送给定事件后调用的侦听器。
以下是最常见的事件:
worker.on('error', (error) => {});
只要 worker 中有未捕获的异常,就会发出 error
事件。然后终止 worker,错误可以作为提供的回调中的第一个参数。
worker.on('exit', (exitCode) => {});
在 worker 退出时会发出 exit
事件。如果在worker中调用了 process.exit()
,那么 exitCode
将被提供给回调。如果 worker 以 worker.terminate()
终止,则代码为1。
worker.on('online', () => {});
只要 worker 停止解析 JavaScript 代码并开始执行,就会发出 online
事件。它不常用,但在特定情况下可以提供信息。
worker.on('message', (data) => {});
只要 worker 将数据发送到父线程,就会发出 message
事件。
现在让我们来看看如何在线程之间共享数据。
在线程之间交换数据
要将数据发送到另一个线程,可以用 port.postMessage()
方法。它的原型如下:
port.postMessage(data[, transferList])
port 对象可以是 parentPort
,也可以是 MessagePort
的实例 —— 稍后会详细讲解。
第一个参数 —— 这里被称为 data
—— 是一个被复制到另一个线程的对象。它可以是复制算法所支持的任何内容。
数据由结构化克隆算法进行复制(包含function的对象引用都会报错DataCloneError:xxxx could not be cloned)。引用自 Mozilla:
它通过递归输入对象来进行克隆,同时保持之前访问过的引用的映射,以避免无限遍历循环。
该算法不复制函数、错误、属性描述符或原型链。还需要注意的是,以这种方式复制对象与使用 JSON 不同,因为它可以包含循环引用和类型化数组,而 JSON 不能。
由于能够复制类型化数组,该算法可以在线程之间共享内存。
server.js
const express = require('express');
const ws = require('ws');
const convertMessage = require('./worker');//引入worker中的方法
const app = express()
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', (socket, req) => {
socket.on('message', message => {
console.log(message);
const port = 3002
app.get('/test', (req, res) => {
//1.接收到test请求,调用convertMessage,发起子线程
convertMessage().then(() => {
//5.converMessage resove后向客户端发送success
res.send('success')
app.get('/', async (req, res) => {
res.send('Hello World!')
//启动服务
const server = app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
worker.js
const { Worker, workerData } = require('worker_threads')
module.exports = function convertMessage() {
return new Promise((resolve, reject) => {
//2.子线程中执行./index.js文件
const worker = new Worker('./index.js');
worker.on('message', (message) => {
//4.接收到子线程通过postMessage传回的message
console.log(message)
resolve()
worker.on('error', reject);
worker.on('exit', (code) => {
//子线程执行完成后触发exit事件
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
index.js
const { parentPort, workerData } = require('worker_threads')
for (let i = 0; i < 100; i++) {
//3.通过主线程的parentPort,向主线程发送消息
parentPort.postMessage(`index.js执行中${i}`)
2、测试结果
后端通过node server.js启动服务,前端通过http://localhost:3002/test发起请求:
后端log如下:
前端结果: