child_process 基础入门

3,364 阅读2分钟

child_process 模块提供了衍生子进程的能力。 此功能主要由 child_process.spawn() 函数提供

以下是使用一些api的小栗子,看不懂也没关系。

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`子进程退出,退出码 ${code}`);
});

默认情况下, stdin、 stdout 和 stderr 的管道会在父 Node.js 进程和衍生的子进程之间建立。

child_process.spawn() 方法会异步地衍生子进程,且不阻塞 Node.js 事件循环。

child_process.spawnSync() 函数则以同步的方式提供了等效的功能。

为方便起见, child_process 模块提供了 child_process.spawn() 和 child_process.spawnSync()的一些同步和异步的替代方法。

这些替代方法中的每一个都是基于 child_process.spawn() 或 child_process.spawnSync() 实现的。

这么看起来就是子进程“万物基于spawn”的意思了嘛

我们来看看其中的一些替代方法。

  • child_process.exec(): 衍生 shell 并且在 shell 中运行命令,当完成时则将 stdout 和 stderr 传给回调函数。

  • child_process.execFile(): 类似于 child_process.exec(),但是默认情况下它会直接衍生命令而不先衍生 shell。

  • child_process.fork(): 衍生新的 Node.js 进程,并调用指定的模块,该模块已建立了 IPC(操作系统知识) 通信通道,可以在父进程与子进程之间发送消息。

以下是不太重要的:

  • child_process.execSync(): child_process.exec() 的同步版本,会阻塞 Node.js 事件循环。

  • child_process.execFileSync(): child_process.execFile() 的同步版本,会阻塞 Node.js 事件循环。

总结起来感觉好像也没多少内容是不是?

汇总:

  • child_process.spawn()
    • child_process.exec()
    • child_process.execFile()
    • child_process.fork()

一个爸爸方法生出三个儿子方法,大家都是子进程内容。都要记住。

每个方法都返回一个 ChildProcess 实例。

这些实例继承了events模块,父进程注册监听器,子进程的生命周期中当发生某些事件时会触发。

child_process.exec() 和 child_process.execFile() 方法还允许指定可选的 callback 函数,当子进程终止时会被调用。

  • 蛋疼的操作系统我还不会

child_process.exec() 和 child_process.execFile() 之间区别的重要性可能因平台而异。

在 Unix 类型的操作系统(Unix、Linux、macOS)上,child_process.execFile() 可以更高效,因为默认情况下它不会衍生 shell。

但是在 Windows 上, .bat 和 .cmd 文件在没有终端的情况下不能自行执行,因此无法使用 child_process.execFile() 启动。

当在 Windows 上运行时,要调用 .bat 和 .cmd 文件,可以使用设置了 shell 选项的 child_process.spawn()、或 child_process.exec()、或衍生 cmd.exe 并将 .bat 或 .cmd 文件作为参数传入(也就是 shell 选项和 child_process.exec() 所做的)。 在任何情况下,如果脚本的文件名包含空格,则需要加上引号。

本来我几乎看不懂,官方这次给的例子非常人道,秒懂了。 直接体验就好了:

// 仅在 Windows 上。
const { spawn } = require('child_process'); 引入子进程的爸爸模块
const bat = spawn('cmd.exe', ['/c', 'my.bat']); // 哦,原来如此,上面那句话就是这个意思去使用。这里返回了个子进程实例

bat.stdout.on('data', (data) => {  
  console.log(data.toString());
});

bat.stderr.on('data', (data) => {
  console.error(data.toString());
});

bat.on('exit', (code) => {
  console.log(`子进程退出,退出码 ${code}`);
});

// 上下都可以在windows上很好使用

const { exec, spawn } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(stdout);
});

-----------------------------------------------------------

// 当文件名中包含空格的脚本时,需要多加引号哦:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
// 或:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
  // ...
});
  • child_process.exec(command[, options][, callback])

    • command: 要执行的命令这个我觉得不用多加解释。
    • options(object)这里就不罗列字典了。
    • callback 当进程终止时调用并传入输出
      • error
      • stdout
      • stderr

衍生 shell,然后在 shell 中执行 command,并缓冲任何产生的输出(不用流)。 传给 exec 函数的 command 字符串会被 shell 直接处理。

传给回调的 stdout 和 stderr 参数会包含子进程的 stdout 和 stderr 输出。 默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传给回调。

const { exec } = require('child_process');
exec('cat *.js 文件 | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`执行的错误: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});
  • child_process.execFile(file[, args][, options][, callback])

    • file 要运行的可执行文件的名称或路径。
    • args 字符串参数的列表。
    • options (Object)
    • callback
      • error
      • stdout
      • stderr

child_process.execFile() 函数类似于 child_process.exec(),但默认情况下不会衍生 shell进程。 指定的可执行文件 file 会被直接衍生作为新的进程,使其比 child_process.exec() 稍微更高效。

const { execFile } = require('child_process');
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
});
  • child_process.fork(modulePath[, args][, options])

    • modulePath 要在子进程中运行的模块。
    • args 字符串参数的列表。
    • options

      child_process.fork() 方法是 child_process.spawn() 的特例,专门用于衍生新的 Node.js 进程。

      与 child_process.spawn() 一样返回 ChildProcess 对象。 区别在于其以及与父进程创建好了信道了。 衍生的 Node.js 子进程独立于父进程,但两者之间建立的 IPC 通信通道除外。

      每个进程都有自己的内存,带有自己的 V8 实例。 由于需要额外的资源分配,因此不建议衍生大量的 Node.js 子进程。

      一时半会也写不完,有缘再改