【问题标题】:node child_process not firing message event节点子进程未触发消息事件
【发布时间】:2022-02-16 19:11:22
【问题描述】:

当我以 commonJs 语法从 parent.js 向 child.js 发送消息时,它可以工作。在 parent.js 我有

//parent.js
const cp = require('child_process');

let child = cp.fork('./child.js');

child.on('message', (message) =>{
    console.log('Parent got message: '+message);
});

// parent sends a message
child.send('Parent sends message');

在 child.js 中我有:

// child.js
process.on('message', (m) => {
    console.log('child got message:', m);

    process.send('child sends message');
});

一切正常,在控制台中我得到了:

child got message: Parent sends message
Parent got message: child sends message

但是当我使用 ES6 导入语法时它停止工作:

import * as cp from 'child_process';

我做错了什么,还是这是一个 nodejs 错误?

我的节点版本是16.13.2 在不工作下,我的意思是终端中的光标在闪烁,但我没有收到任何消息,也没有收到任何错误。

【问题讨论】:

    标签: node.js child-process


    【解决方案1】:

    import foo from 'foo' 语法仅在 ECMAScript 模块中受支持。从 Node v12 开始支持 ECMAScript 模块(或简称 ESM)(没有实验标志)。然而,NodeJS 传统上使用 CommonJS (CJS) 模块格式 (const foo = require('foo');)。为了支持这两种格式并确保它们之间的互操作性,NodeJS 要求您(开发人员)明确识别您的文件属于这两种格式中的哪一种。

    要向 NodeJS 表明您的文件是 ESM 格式,您可以使用以下选项之一:

    1. 使用.mjs 扩展名而不是.js 命名您的文件。默认情况下,NodeJS 将所​​有 .js 文件视为 CJS 模块,只有名为 .mjs 的文件被视为 ES 模块。以上示例中带有import ... 的文件应分别命名为parent.mjschild.mjs
    2. 在您的package.json 中添加"type": "module"。这将使 NodeJS 将项目中的所有 .js 文件视为 ES 模块。如果项目中的所有(或几乎所有)文件都使用 import ... 语法,请使用此选项。如果您需要在任何文件中使用require('foo'); 语法,则必须改为使用.cjs 扩展名。
    3. 使用--input-type=module 标志运行节点进程,从STDIN 传递代码。在大多数情况下,此选项是不切实际的。虽然您可以通过运行:node --input-type="module" < parent.js 来使用它,但请注意,此处的文件未作为参数传递,仅将其内容重定向到节点进程的 STDIN。

    【讨论】:

    • 感谢您的回答。在我的 package.json 中,我已经设置了 type: module,但是正如您所建议的,我也将文件扩展名从 .js 更改为 .mjs,并使用给定选项运行 parent.mjs 文件,但这也没有帮助,我仍然在我的控制台中没有任何错误。运行 parent.mjs 后,我只看到闪烁的光标。我的节点版本是:v16.13.2。
    • 哦,我明白了。好的,从package.json 中删除type: module,将父级重命名为parent.mjs,并将子级命名为child.js,确保child.js 作为CJS 模块运行。在这个设置中,一切都会很好。该问题是由 ESM 模块的加载方式引起的。当父级调用child.send 时,child.js 仍在加载中,process.on 尚未执行。消息只是丢失了,序列永远不会触发。
    • 您也可以通过将 type: module 留在 package.json 中来解决此问题,但将 child 重命名为 child.cjs。或者,通过在父节点中运行 child.send 并延迟几毫秒。然而,在我看来,最好的方法是从 child 触发序列。当然,父进程肯定在运行,所以每当子进程上线时,它都会向父进程发送一条消息,从而触发序列。
    • 把代码放在setTimeout下就解决了,谢谢d_shiv!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2016-04-26
    • 1970-01-01
    相关资源
    最近更新 更多