Node.js子进程入门
在本教程中,我们将讨论如何使用子进程来启动另一个进程,以避免执行程序时出现延迟。
简介
Node.js程序在执行时是在单线程上运行的。执行数以百万计的进程会导致延迟/阻塞,因此需要一个解决方案。解决这种延迟的方法之一是使用Node.js的子进程。
前提条件
本教程需要JavaScript和Node.js的基本知识。
开始学习
Node.js是单线程的,这意味着无论你的服务器多么强大,它在给定时间内只支持几个负载。这就是子进程的作用。它们有助于解决这些延迟问题,从而提高程序的总体性能。
子进程模块
子进程模块有几种方法,我们可以用它们来创建其他进程。
在本教程中,我们将介绍以下两个主要方法。
- child_process.exec()
- child_process.spoon()
使用exec() 方法创建子进程
child_process.exec() 方法创建一个新的shell进程。然后它使用这个shell来执行命令。这些执行命令的输出被保存在一个内存缓冲区中。
然后,这个输出可以通过传递给exec() 方法的回调函数来访问。让我们看一个例子。
注意:在本教程中,我们使用Node.js强大的
[REPL](https://nodejs.dev/learn/how-to-use-the-nodejs-repl)命令行工具来运行/测试我们的结果,但你可以根据你的要求自由创建文件。
通过在终端运行以下命令启动你的REPL 。
$ node
输出。
$ node
Welcome to Node.js v13.14.0.
Type ".help" for more information.
>
接下来,让我们通过运行以下命令导入child_process 模块。
...................
> const {exec} = require('child_process');
undefined
>
让我们继续,并记录到我们的控制台exec 常数。
输出。
> const {exec} = require(`child_process`);
undefined
> console.log(exec);
[Function: exec] //output
undefined
>
你注意到,
exec常量的类型是Function对象。
现在让我们看一下child_process.exec()方法的语法。
child_process.exec(command[, options][, callback])
这个方法需要2个参数,command 作为第一个参数,有可选的选项和一个callback 函数。command 参数是字符串类型的,期望执行一条命令,例如,一条列出你的目录文件的命令。
options 是一个对象,它需要几个其他的方法,例如,获得子进程的当前工作目录process.cwd() 。callback 是一个函数,当一个进程被终止时应该被调用。
它接受以下3个参数。
- error--返回一个类型为
Error的错误。 - stdout|-返回一个字符串或一个缓冲区,处理二进制数据。
- stderr|- 返回一个字符串/缓冲区。
现在我们已经介绍了这个方法的基本工作原理,让我们看看一个工作实例。
在你的REPL ,添加以下脚本来执行ls 命令,列出你当前目录下的文件夹和文件。
> exec('ls -lh', (error, stdout, stderr) => {
... if (err) {
..... console.error(err);
..... return;
..... }
...
... if (stderr) {
... console.error(stderr);
... return;
... }
...
... console.log(stdout);
... });
>
undefined
>
输出。
> stdout:
total 8.0K
-rwxrwxrwx 1 root root 612 Apr 2 11:57 index.nginx-debian.html
lrwxrwxrwx 1 root root 21 Apr 2 12:54 phpmyadmin -> /usr/share/phpmyadmin
drwxrwxr-x 5 wen wen 4.0K Apr 2 12:24 project
从上面的脚本中:
我们首先导入child_process 模块,使用一种极其简洁的语法,即[JavaScript的结构化]。
child_process.exec() 预计有2个参数,命令和回调函数。回调函数需要3个参数: , , 和 。error stdout stderr
在成功执行时,error 返回null ,否则返回一个Error 的实例。
stdout 和stderr 包含子进程的输出,在UTF-8中解码,如上面的输出所示。
使用'child_process.spoon()'创建子进程
与child_process.exec() ,这个方法需要使用流,即数据是通过流API返回的。
因此,为了获得所需的结果,我们要监听流事件。
让我们看一个例子。
在你的REPL ,运行以下命令。
Type ".help" for more information.
> const { spawn } = require('child_process');
undefined
>
> const spawned_child = spawn('cat', ['child.js']);
undefined
>
在上面的脚本中,我们首先导入child_process 模块。结果被分配给一个去结构化的常量,spawn 。
然后我们通过调用spawn() 方法创建一个子进程。这个方法接受两个参数,命令和可选的选项。
产生的输出被分配给一个spawned_child 常量。
同样重要的是要注意,spawn函数的调用将总是返回ChildProcess实例。
$ node
Welcome to Node.js v13.14.0.
Type ".help" for more information.
> const fs = require('fs')
undefined
> const { spawn } = require('child_process')
undefined
> const filename ='child.js'
undefined
>
> fs.watch(filename, () => {
... const ls = spawn('ls', ['-lh', filename])
... ls.stdout.pipe(process.stdout)
... })
<ref *1> FSWatcher {
_events: [Object: null prototype] { change: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
_handle: FSEvent {
onchange: [Function (anonymous)],
[Symbol(owner_symbol)]: [Circular *1]
},
[Symbol(kCapture)]: false
}
在上面的脚本中,我们已经创建了一个文件child.js 。我们正在观察这个文件的变化,即编辑或删除。每当有变化时,我们就运行命令ls -lh 。
然后,我们将主进程的输出从子进程中引出。
请注意,如果我们不把主进程的结果通过管道输出,就不会有输出显示。
总结
在本教程中,我们已经看到了如何使用child_process.exec() 和child_process.spawn() 来创建子进程。
还有其他一些方法,如child_process.fork() ,它是child_process.spawn() 方法的一个变种。