解决方案
我们使用 node-typesafe-worker-messages 这个库
来实现 typescript 支持和发送消息的 callback
安装
$ pnpm add node-typesafe-worker-messages -D
使用
我们需要先定义以下消息的类型,因为主进程会发消息给 worker,
worker 也会发消息给主进程 ,因此我们需要定义两个消息类型
⚠️ 注意,消息类型必须用 Promise 作为返回值,即使你返回的是 void
// types.ts
// 定义从主进程发送给每个 worker 的消息类型
type ParentMessage = {
getWorkProcessId(): Promise<number>;
getWorkTasksList(): Promise<string[]>;
printDataFromWorker(
args: number,
args2: number,
args3: number
): Promise<void>;
};
// 定义从 worker 发送给主进程的消息类型
type WorkerMessage = {
getMainProcessId(): Promise<number>;
getUserInfoById(id: string): Promise<string>;
};
主进程中使用
import { TypeSafeWorkerMessagesInMain } from "node-typesafe-worker-messages";
import type { ParentMessage, WorkerMessage } from "./types.ts";
// 这里将之前定义好的两个类型当成泛型传递过去
const worker = new TypeSafeWorkerMessagesInMain<ParentMessage, WorkerMessage>(
// 这个类接收的参数和返回值跟 worker_threads 是一样的
// 它只是对 worker_threads 进行了一层包裹
join(__dirname, "worker.cjs"),
{
workerData: { foo: "bar" },
}
);
// 所有方法都与 worker_threads 一样
//
worker.on("online", () => {
// 但是我们提供了两个额外的方法 handle 和 send,
// 定义他们的目的是为了消息传递时的类型约束和 callbakc 实现
// handle 是用于处理消息
// send 是用于发送消息
worker.handle("getMainProcessId", () => {
return Promise.resolve(1234);
});
worker.handle("getUserInfoById", () => {
return Promise.resolve("Carl");
});
worker.send("printDataFromWorker", 1, 2, 3);
worker.send("getWorkTasksList").then((res) => {
console.log(res, "getWorkTasksList callback");
});
// 当然你还可以继续使用 on("message") 来监听消息
// 记住,TypeSafeWorkerMessagesInMain 只是对 worker_threads 的一层包裹
worker.on("message", (action) => {
if (action === "close") {
worker.terminate();
}
});
});
Worker
此时你需要手动关闭它
import { TypeSafeWorkerMessagesInWorker } from "node-typesafe-worker-messages";
import type { ParentMessage, WorkerMessage } from "./types.ts";
const _: MessagePort = parentPort as MessagePort;
const parent = TypeSafeWorkerMessagesInWorker<ParentMessage, WorkerMessage>(_);
parent.handle("getWorkProcessId", () => {
return Promise.resolve(123);
});
parent.handle("printDataFromWorker", (...args) => {
console.log(args, "from worker");
});
parent.handle("getWorkTasksList", () => {
return Promise.resolve(["1", "2222"]);
});
setTimeout(() => {
parent.send("getUserInfoById", "44").then((res) => {
console.log(res, "getUserInfoById callback from parent with callback!");
parent.postMessage("close");
});
}, 2000);