在 Node.js 中,child_process 模块被用来启动和控制子进程。Node.js 是单线程的,但是可以通过创建子进程来扩展其能力。child_process 模块提供了函数,可以在新的进程中运行 shell 命令或其他进程,并在 Node.js 主进程中控制其输入输出和生命周期。
本文将对 child_process 模块的用法进行详细解析,包括启动进程、输入输出控制、进程通信、集群和异常处理。
启动进程
child_process 模块提供了 4 个函数可以启动新的进程:
exec()
- 启动一个 shell 并运行命令,等待它执行完毕,并返回所有的输出结果。execFile()
- 直接运行一个文件,而不是通过 shell 进行解释。spawn()
- 启动一个新的进程。与exec()
不同,它不等待命令完成并立即返回一个 ChildProcess 对象。fork()
- 创建一个与当前进程相同的进程,并在新的进程中运行另一个模块(Node.js 文件)。与spawn()
不同,它不需要指定命令和选项。
下面是一些简单的例子:
exec()
-- -------------------- ---- ------- ----- - ---- - - ------------------------- -------- ----- ------- ------- ------- -- - -- ------- - -------------------- ----------- ------- - -------------------- ------------ -------------------- ------------ ---
这个例子中,我们使用 exec()
启动了一个 shell 并运行了 ls -lh
命令。当该命令执行完成时,我们会得到一个回调,并且可以查看该命令的输出结果。
spawn()
-- -------------------- ---- ------- ----- - ----- - - ------------------------- ----- -- - ----------- ------- --------- -------------------- ---- -- - -------------------- ---------- --- -------------------- ---- -- - ---------------------- ---------- --- -------------- ---- -- - -------------------- ---------- ---
这个例子中,我们启动了 ls -lh /usr
命令。我们可以监听 stdout
和 stderr
事件来获取输出信息,并监听 close
事件来得知子进程何时退出。
输入输出控制
子进程的输入和输出可以通过 stdin/stdout 和 stderr 句柄进行控制。下面是示例代码:
-- -------------------- ---- ------- ----- - ----- - - ------------------------- ----- -- - ----------- ------- --------- --------------------- --------- --------------- -------------------- ---- -- - -------------------- ---------- --- -------------------- ---- -- - ---------------------- ---------- --- -------------- ---- -- - -------------------- ---------- ---
在这个例子中,我们向子进程的标准输入流(stdin)写入了字符串,并通过 end()
终止了输入流。然后,我们监听了 stdout
和 stderr
事件。
进程通信
子进程和主进程之间可以通过 stdin/stdout 和 stderr 句柄进行通信。下面是一个示例:
main.js:
-- -------------------- ---- ------- ----- - ----- - - ------------------------- ----- ----- - ------------- ------------- - ------ -------- ------- --------------- --- ---------------------- ----------------------- ---- -- - ------------------- ---------- --- ----------------------- ---- -- - --------------------- ---------- ---
child.js:
console.log('子进程输出!'); process.stdin.on('data', data => { console.log(`子进程接收到: ${data}`); process.stdout.write(`输出: ${data}`); process.stdout.write(`输出2: ${data}`); });
在这个例子中,我们通过 spawn()
启动了一个 child.js 子进程,并在主进程中监听了其 stdout
和 stderr
事件。在子进程中,我们为 stdin
句柄添加了一个事件监听器,并在接收到数据后向 stdout
句柄写入了相同的数据。
集群
Node.js 可以通过 cluster 模块创建集群。cluster 模块使用 child_process 上的 fork() 方法来实现多个 Node.js 进程间的通信。以下是一个集群的例子:
-- -------------------- ---- ------- ----- ------- - ------------------- ----- ---- - ---------------- ----- ------- - ---------------------------- -- ------------------ - ---------------- -------------- ------- -- ------ --- ---- - - -- - - -------- ---- - --------------- - ------------------ -------- ----- ------- -- - ----------------- --------------------- ------ --- - ---- - -- ---------- --- -- -- --------- ---- --- ----------------------- ---- -- - ------------------- ------------------ ---------------- ----------------- -------------- ------ -
在这个例子中,我们使用 cluster.isMaster
属性来决定进程是主进程还是工作进程。主进程负责启动工作进程,而工作进程则启动一个简单的 HTTP 服务器。从工作进程中可以使用 cluster.worker.id 属性获取其 ID。
异常处理
child_process 启动进程的时候,可能会抛出异常。这些异常可以通过 try-catch 块或者 error 事件来捕获。
下面是一个示例:
-- -------------------- ---- ------- ----- - ----- - - ------------------------- ----- -- - ----------- ------- --------- -- -------------- -------------- ----- -- - ---------------------- ----------- --- -------------------- ---- -- - -------------------- ---------- --- -------------------- ---- -- - ---------------------- ---------- --- -------------- ---- -- - -------------------- ---------- ---
在这个例子中,我们将输入一个不存在的路径,将会抛出一个错误。通过监听 error
事件的方式,我们就可以在这种情况下执行额外的代码。
结论
child_process 模块是 Node.js 中非常重要的模块之一,可以实现很多有趣的功能,如多进程计算、集群等。在实践中需要仔细考虑子进程和主进程之间的通信,并确保正确处理异常。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67525c5f8bd460d3ad934e38