Node.js worker_threads Promise 跨线程通信报ERR_INVALID_ARG_TYPE错误
报错根因
- Worker线程启动时是独立的执行上下文,默认不会继承主线程启动时的命令行参数,worker内部执行
workLoad时读取的process.argv[2]实际为undefined。 - 后续调用
crypto.createHash("sha256").update(undefined)时,因为update方法要求入参必须是字符串、Buffer、TypedArray或DataView类型,直接触发ERR_INVALID_ARG_TYPE报错。 - 由于Promise链没有配置错误捕获逻辑,异常被抛出后没有处理,最终触发
UnhandledPromiseRejectionWarning,且因为异常发生在参数读取阶段,根本没有走到文件读写、resolve返回数据的逻辑,最终postMessage发送的内容也为undefined,完全匹配报错提示。 - 现有代码逻辑本身和需求不匹配:原本需要的是主线程Promise处理完成后拿到的data传递给worker、worker回传结果,但当前代码完全没有跨线程传参的逻辑,反而让worker自行读取无法访问的参数。
可运行的修复代码
const { isMainThread, parentPort, Worker, workerData } = require("worker_threads"); const fs = require("fs"); const crypto = require("crypto"); const { join } = require("path"); // 调整workLoad为接收参数形式,不再内部读取无法获取的进程参数 const workLoad = async (firstArg, secondArg) => { return new Promise((resolve, reject) => { try { if (!firstArg) reject(new Error("必须传入有效的目录路径参数")); const encodedSha256 = crypto .createHash("sha256") .update(firstArg) .digest("hex"); const base64 = Buffer.from(secondArg).toString("base64"); const encodeData = `${encodedSha256}\n${base64}`; fs.writeFileSync(join(firstArg, secondArg), encodeData, { encoding: "utf-8", }); const data = fs.readFileSync(join(firstArg, secondArg), { encoding: "utf-8", }); resolve(data); } catch (error) { reject(error); } }); }; if (isMainThread) { // 主线程创建Worker时,通过workerData把需要传递给worker的参数透传 const worker = new Worker(__filename, { workerData: { firstArg: process.argv[2], secondArg: process.argv[3] ?? Math.random().toString(36).substring(8) + ".txt" } }); // 监听worker回传的消息 worker.on("message", (message) => console.log("Worker回传结果:", message)); // 必须监听worker的error事件,否则worker抛错会导致进程退出 worker.on("error", (err) => console.error("Worker异常:", err)); } else { // worker线程直接从workerData拿主线程透传的参数,不再读自己的process.argv const { firstArg, secondArg } = workerData; workLoad(firstArg, secondArg) .then((res) => parentPort.postMessage(res)) // 捕获所有Promise异常,避免未处理的rejection警告 .catch(err => parentPort.postMessage(`处理失败:${err.message}`)); }
关键注意事项
- Worker的初始参数传递统一使用
new Worker()配置项中的workerData字段,该字段传递的内容需要符合结构化克隆算法要求,worker线程启动后可以直接通过require("worker_threads").workerData读取,不需要做额外序列化。 - 所有跨线程的通信逻辑都要配套错误捕获:Worker端的Promise链必须加
.catch(),主线程必须给Worker实例绑定error事件监听,否则任意未捕获的异常都会直接导致Node进程退出。 - 如果需要严格实现“主线程先通过Promise处理得到data,再传给worker处理”的流程,只需要在主线程创建Worker之前,先执行对应的Promise逻辑拿到待传递的data,再把这个data放到
workerData配置项中即可,worker端拿到data后完成处理再通过parentPort.postMessage回传主线程。
内容的提问来源于stack exchange,提问作者Joshua Ramos
相关产品推荐
相关产品推荐

