子程序#

穩定性:2 - 穩定

原始碼: lib/child_process.js

node:child_process 模組提供了以類似於 popen(3) 但不完全相同的方式衍生子程序的能力。這個功能主要由 child_process.spawn() 函式提供。

const { spawn } = require('node: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(`child process exited with code ${code}`);
});import { spawn } from 'node: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(`child process exited with code ${code}`);
});

預設情況下,父 Node.js 程序和衍生的子程序之間會建立用於 stdinstdoutstderr 的管道。這些管道的容量有限(且因平臺而異)。如果子程序向 stdout 寫入的資料超出了該限制而輸出未被捕獲,子程序將阻塞,等待管道緩衝區接受更多資料。這與 shell 中管道的行為相同。如果輸出不會被消費,請使用 { stdio: 'ignore' } 選項。

如果 options 物件中存在 env,則使用 options.env.PATH 環境變數進行命令查詢。否則,使用 process.env.PATH。如果在設定 options.env 時沒有設定 PATH,則在 Unix 上會在預設搜尋路徑 /usr/bin:/bin 上執行查詢(請參閱您作業系統的 execvpe/execvp 手冊),在 Windows 上則使用當前程序的環境變數 PATH

在 Windows 上,環境變數不區分大小寫。Node.js 會按字典順序對 env 的鍵進行排序,並使用第一個不區分大小寫匹配的鍵。只有(按字典順序)第一個條目會被傳遞給子程序。當向 env 選項傳遞包含同一鍵的多個變體(如 PATHPath)的物件時,這可能會在 Windows 上導致問題。

child_process.spawn() 方法非同步地衍生子程序,不會阻塞 Node.js 事件迴圈。child_process.spawnSync() 函式以同步方式提供了等效的功能,它會阻塞事件迴圈,直到衍生的程序退出或被終止。

為方便起見,node:child_process 模組提供了幾個同步和非同步的替代方案來替代 child_process.spawn()child_process.spawnSync()。這些替代方案都是在 child_process.spawn()child_process.spawnSync() 的基礎上實現的。

對於某些用例,例如自動化 shell 指令碼,同步的對應方法可能更方便。然而,在許多情況下,同步方法可能會對效能產生重大影響,因為它們會在衍生程序完成時阻塞事件迴圈。

非同步程序建立#

child_process.spawn()child_process.fork()child_process.exec()child_process.execFile() 方法都遵循其他 Node.js API 中典型的非同步程式設計模式。

每個方法都返回一個 ChildProcess 例項。這些物件實現了 Node.js 的 EventEmitter API,允許父程序註冊監聽函式,這些函式在子程序生命週期中發生特定事件時被呼叫。

child_process.exec()child_process.execFile() 方法還允許指定一個可選的 callback 函式,該函式在子程序終止時被呼叫。

在 Windows 上衍生 .bat.cmd 檔案#

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() 就是這麼做的)。在任何情況下,如果指令碼檔名包含空格,都需要用引號引起來。

// OR...
const { exec, spawn } = require('node:child_process');

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

// Script with spaces in the filename:
const bat = spawn('"my script.cmd" a b', { shell: true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
  // ...
});// OR...
import { exec, spawn } from 'node:child_process';

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

// Script with spaces in the filename:
const bat = spawn('"my script.cmd" a b', { shell: true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
  // ...
});

child_process.exec(command[, options][, callback])#

衍生一個 shell,然後在該 shell 中執行 command,並緩衝任何生成的輸出。傳遞給 exec 函式的 command 字串由 shell 直接處理,特殊字元(因 shell 而異)需要相應處理。

const { exec } = require('node:child_process');

exec('"/path/to/test file/test.sh" arg1 arg2');
// Double quotes are used so that the space in the path is not interpreted as
// a delimiter of multiple arguments.

exec('echo "The \\$HOME variable is $HOME"');
// The $HOME variable is escaped in the first instance, but not in the second.import { exec } from 'node:child_process';

exec('"/path/to/test file/test.sh" arg1 arg2');
// Double quotes are used so that the space in the path is not interpreted as
// a delimiter of multiple arguments.

exec('echo "The \\$HOME variable is $HOME"');
// The $HOME variable is escaped in the first instance, but not in the second.

切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

如果提供了 callback 函式,它會以 (error, stdout, stderr) 作為引數被呼叫。成功時,error 將為 null。出錯時,error 將是 Error 的一個例項。error.code 屬性將是程序的退出碼。按照慣例,任何非 0 的退出碼都表示錯誤。error.signal 將是終止程序的訊號。

傳遞給回撥函式的 stdoutstderr 引數將包含子程序的 stdout 和 stderr 輸出。預設情況下,Node.js 會將輸出解碼為 UTF-8 並將字串傳遞給回撥函式。encoding 選項可用於指定用於解碼 stdout 和 stderr 輸出的字元編碼。如果 encoding'buffer' 或無法識別的字元編碼,則會向回撥函式傳遞 Buffer 物件。

const { exec } = require('node:child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});import { exec } from 'node:child_process';
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});

如果 timeout 大於 0,當子程序執行時間超過 timeout 毫秒時,父程序將傳送由 killSignal 屬性標識的訊號(預設為 'SIGTERM')。

exec(3) POSIX 系統呼叫不同,child_process.exec() 不會替換現有程序,而是使用 shell 來執行命令。

如果此方法作為其 util.promisify()ed 版本被呼叫,它會返回一個解析為帶有 stdoutstderr 屬性的 ObjectPromise。返回的 ChildProcess 例項作為 child 屬性附加到 Promise 上。如果發生錯誤(包括任何導致退出碼不為 0 的錯誤),將返回一個被拒絕的 promise,其 error 物件與回撥函式中的相同,但額外增加了 stdoutstderr 兩個屬性。

const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();import { promisify } from 'node:util';
import child_process from 'node:child_process';
const exec = promisify(child_process.exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();

如果啟用了 signal 選項,在相應的 AbortController 上呼叫 .abort() 類似於在子程序上呼叫 .kill(),只是傳遞給回撥的錯誤將是一個 AbortError

const { exec } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();import { exec } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();

child_process.execFile(file[, args][, options][, callback])#

  • file <string> 要執行的可執行檔案的名稱或路徑。
  • args <string[]> 字串引數列表。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • env <Object> 環境變數鍵值對。預設值: process.env
    • encoding <string> 預設值: 'utf8'
    • timeout <number> 預設值: 0
    • maxBuffer <number> stdout 或 stderr 上允許的最大資料量(以位元組為單位)。如果超出,子程序將被終止,任何輸出都將被截斷。請參閱 maxBuffer 與 Unicode 中的注意事項。預設值: 1024 * 1024
    • killSignal <string> | <integer> 預設值: 'SIGTERM'
    • uid <number> 設定程序的使用者標識(參見 setuid(2))。
    • gid <number> 設定程序的組標識(參見 setgid(2))。
    • windowsHide <boolean> 隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值: false
    • windowsVerbatimArguments <boolean> 在 Windows 上不對引數進行引用或轉義。在 Unix 上被忽略。預設值: false
    • shell <boolean> | <string> 如果為 true,則在 shell 中執行 command。在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。可以指定一個不同的 shell 作為字串。請參閱Shell 要求預設 Windows shell預設值: false (無 shell)。
    • signal <AbortSignal> 允許使用 AbortSignal 中止子程序。
  • callback <Function> 在程序終止時使用輸出呼叫。
  • 返回:<ChildProcess>

child_process.execFile() 函式與 child_process.exec() 類似,不同之處在於它預設不衍生 shell。相反,指定的可執行檔案 file 被直接衍生為一個新程序,這使得它比 child_process.exec() 稍微高效一些。

支援與 child_process.exec() 相同的選項。由於不衍生 shell,因此不支援 I/O 重定向和檔案通配等行為。

const { execFile } = require('node:child_process');
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
});import { execFile } from 'node:child_process';
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
});

傳遞給回撥函式的 stdoutstderr 引數將包含子程序的 stdout 和 stderr 輸出。預設情況下,Node.js 會將輸出解碼為 UTF-8 並將字串傳遞給回撥函式。encoding 選項可用於指定用於解碼 stdout 和 stderr 輸出的字元編碼。如果 encoding'buffer' 或無法識別的字元編碼,則會向回撥函式傳遞 Buffer 物件。

如果此方法作為其 util.promisify()ed 版本被呼叫,它會返回一個解析為帶有 stdoutstderr 屬性的 ObjectPromise。返回的 ChildProcess 例項作為 child 屬性附加到 Promise 上。如果發生錯誤(包括任何導致退出碼不為 0 的錯誤),將返回一個被拒絕的 promise,其 error 物件與回撥函式中的相同,但額外增加了 stdoutstderr 兩個屬性。

const util = require('node:util');
const execFile = util.promisify(require('node:child_process').execFile);
async function getVersion() {
  const { stdout } = await execFile('node', ['--version']);
  console.log(stdout);
}
getVersion();import { promisify } from 'node:util';
import child_process from 'node:child_process';
const execFile = promisify(child_process.execFile);
async function getVersion() {
  const { stdout } = await execFile('node', ['--version']);
  console.log(stdout);
}
getVersion();

如果啟用了 shell 選項,切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

如果啟用了 signal 選項,在相應的 AbortController 上呼叫 .abort() 類似於在子程序上呼叫 .kill(),只是傳遞給回撥的錯誤將是一個 AbortError

const { execFile } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = execFile('node', ['--version'], { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();import { execFile } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const child = execFile('node', ['--version'], { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();

child_process.fork(modulePath[, args][, options])#

  • modulePath <string> | <URL> 在子程序中執行的模組。
  • args <string[]> 字串引數列表。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • detached <boolean> 準備子程序以獨立於其父程序執行。具體行為取決於平臺(參見 options.detached)。
    • env <Object> 環境變數鍵值對。預設值: process.env
    • execPath <string> 用於建立子程序的可執行檔案。
    • execArgv <string[]> 傳遞給可執行檔案的字串引數列表。預設值: process.execArgv
    • gid <number> 設定程序的組標識(參見 setgid(2))。
    • serialization <string> 指定用於在程序間傳送訊息的序列化型別。可能的值為 'json''advanced'。更多詳情請參見高階序列化預設值: 'json'
    • signal <AbortSignal> 允許使用 AbortSignal 關閉子程序。
    • killSignal <string> | <integer> 當衍生的程序因超時或中止訊號被殺死時使用的訊號值。預設值: 'SIGTERM'
    • silent <boolean> 如果為 true,子程序的 stdin、stdout 和 stderr 將被管道傳輸到父程序,否則它們將從父程序繼承,更多詳情請參見 child_process.spawn()stdio'pipe''inherit' 選項。預設值: false
    • stdio <Array> | <string> 參見 child_process.spawn()stdio。當提供此選項時,它會覆蓋 silent。如果使用陣列變體,它必須只包含一個值為 'ipc' 的項,否則將丟擲錯誤。例如 [0, 1, 2, 'ipc']
    • uid <number> 設定程序的使用者標識(參見 setuid(2))。
    • windowsVerbatimArguments <boolean> 在 Windows 上不對引數進行引用或轉義。在 Unix 上被忽略。預設值: false
    • timeout <number> 程序被允許執行的最長時間(以毫秒為單位)。預設值: undefined
  • 返回:<ChildProcess>

child_process.fork() 方法是 child_process.spawn() 的一個特例,專門用於衍生新的 Node.js 程序。與 child_process.spawn() 一樣,返回一個 ChildProcess 物件。返回的 ChildProcess 將有一個內建的額外通訊通道,允許在父子程序之間來回傳遞訊息。詳情請參見 subprocess.send()

請記住,衍生的 Node.js 子程序獨立於父程序,除了兩者之間建立的 IPC 通訊通道。每個程序都有自己的記憶體和自己的 V8 例項。由於需要額外的資源分配,不建議衍生大量的子 Node.js 程序。

預設情況下,child_process.fork() 將使用父程序的 process.execPath 來衍生新的 Node.js 例項。options 物件中的 execPath 屬性允許使用替代的執行路徑。

使用自定義 execPath 啟動的 Node.js 程序將使用環境變數 NODE_CHANNEL_FD 在子程序上標識的檔案描述符(fd)與父程序通訊。

fork(2) POSIX 系統呼叫不同,child_process.fork() 不會克隆當前程序。

child_process.fork() 不支援 child_process.spawn() 中可用的 shell 選項,如果設定了該選項將被忽略。

如果啟用了 signal 選項,在相應的 AbortController 上呼叫 .abort() 類似於在子程序上呼叫 .kill(),只是傳遞給回撥的錯誤將是一個 AbortError

const { fork } = require('node:child_process');
const process = require('node:process');

if (process.argv[2] === 'child') {
  setTimeout(() => {
    console.log(`Hello from ${process.argv[2]}!`);
  }, 1_000);
} else {
  const controller = new AbortController();
  const { signal } = controller;
  const child = fork(__filename, ['child'], { signal });
  child.on('error', (err) => {
    // This will be called with err being an AbortError if the controller aborts
  });
  controller.abort(); // Stops the child process
}import { fork } from 'node:child_process';
import process from 'node:process';

if (process.argv[2] === 'child') {
  setTimeout(() => {
    console.log(`Hello from ${process.argv[2]}!`);
  }, 1_000);
} else {
  const controller = new AbortController();
  const { signal } = controller;
  const child = fork(import.meta.url, ['child'], { signal });
  child.on('error', (err) => {
    // This will be called with err being an AbortError if the controller aborts
  });
  controller.abort(); // Stops the child process
}

child_process.spawn(command[, args][, options])#

  • command <string> 要執行的命令。
  • args <string[]> 字串引數列表。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • env <Object> 環境變數鍵值對。預設值: process.env
    • argv0 <string> 顯式設定傳送給子程序的 argv[0] 的值。如果未指定,將設定為 command
    • stdio <Array> | <string> 子程序的 stdio 配置(參見 options.stdio)。
    • detached <boolean> 準備子程序以獨立於其父程序執行。具體行為取決於平臺(參見 options.detached)。
    • uid <number> 設定程序的使用者標識(參見 setuid(2))。
    • gid <number> 設定程序的組標識(參見 setgid(2))。
    • serialization <string> 指定用於在程序間傳送訊息的序列化型別。可能的值為 'json''advanced'。更多詳情請參見高階序列化預設值: 'json'
    • shell <boolean> | <string> 如果為 true,則在 shell 中執行 command。在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。可以指定一個不同的 shell 作為字串。請參閱Shell 要求預設 Windows shell預設值: false (無 shell)。
    • windowsVerbatimArguments <boolean> 在 Windows 上不對引數進行引用或轉義。在 Unix 上被忽略。當指定 shell 並且是 CMD 時,此選項會自動設定為 true預設值: false
    • windowsHide <boolean> 隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值: false
    • signal <AbortSignal> 允許使用 AbortSignal 中止子程序。
    • timeout <number> 程序被允許執行的最長時間(以毫秒為單位)。預設值: undefined
    • killSignal <string> | <integer> 當衍生的程序因超時或中止訊號被殺死時使用的訊號值。預設值: 'SIGTERM'
  • 返回:<ChildProcess>

child_process.spawn() 方法使用給定的 command 衍生一個新程序,命令列引數在 args 中。如果省略,args 預設為一個空陣列。

如果啟用了 shell 選項,切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

第三個引數可用於指定附加選項,預設值如下:

const defaults = {
  cwd: undefined,
  env: process.env,
}; 

使用 cwd 指定衍生程序的工作目錄。如果未給出,則預設繼承當前工作目錄。如果給出,但路徑不存在,子程序會發出一個 ENOENT 錯誤並立即退出。當命令不存在時也會發出 ENOENT

使用 env 指定對新程序可見的環境變數,預設為 process.env

env 中的 undefined 值將被忽略。

執行 ls -lh /usr,捕獲 stdoutstderr 和退出碼的示例:

const { spawn } = require('node: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(`child process exited with code ${code}`);
});import { spawn } from 'node: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(`child process exited with code ${code}`);
});

示例:一種非常複雜的方式來執行 ps ax | grep ssh

const { spawn } = require('node:child_process');
const ps = spawn('ps', ['ax']);
const grep = spawn('grep', ['ssh']);

ps.stdout.on('data', (data) => {
  grep.stdin.write(data);
});

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

ps.on('close', (code) => {
  if (code !== 0) {
    console.log(`ps process exited with code ${code}`);
  }
  grep.stdin.end();
});

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

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

grep.on('close', (code) => {
  if (code !== 0) {
    console.log(`grep process exited with code ${code}`);
  }
});import { spawn } from 'node:child_process';
const ps = spawn('ps', ['ax']);
const grep = spawn('grep', ['ssh']);

ps.stdout.on('data', (data) => {
  grep.stdin.write(data);
});

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

ps.on('close', (code) => {
  if (code !== 0) {
    console.log(`ps process exited with code ${code}`);
  }
  grep.stdin.end();
});

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

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

grep.on('close', (code) => {
  if (code !== 0) {
    console.log(`grep process exited with code ${code}`);
  }
});

檢查 spawn 失敗的示例:

const { spawn } = require('node:child_process');
const subprocess = spawn('bad_command');

subprocess.on('error', (err) => {
  console.error('Failed to start subprocess.');
});import { spawn } from 'node:child_process';
const subprocess = spawn('bad_command');

subprocess.on('error', (err) => {
  console.error('Failed to start subprocess.');
});

某些平臺(macOS、Linux)將使用 argv[0] 的值作為程序標題,而其他平臺(Windows、SunOS)將使用 command

Node.js 在啟動時會用 process.execPath 覆蓋 argv[0],因此 Node.js 子程序中的 process.argv[0] 將與從父程序傳遞給 spawnargv0 引數不匹配。請改用 process.argv0 屬性來檢索它。

如果啟用了 signal 選項,在相應的 AbortController 上呼叫 .abort() 類似於在子程序上呼叫 .kill(),只是傳遞給回撥的錯誤將是一個 AbortError

const { spawn } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const grep = spawn('grep', ['ssh'], { signal });
grep.on('error', (err) => {
  // This will be called with err being an AbortError if the controller aborts
});
controller.abort(); // Stops the child processimport { spawn } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const grep = spawn('grep', ['ssh'], { signal });
grep.on('error', (err) => {
  // This will be called with err being an AbortError if the controller aborts
});
controller.abort(); // Stops the child process
options.detached#

在 Windows 上,將 options.detached 設定為 true 使得子程序可以在父程序退出後繼續執行。子程序將有自己的控制檯視窗。一旦為子程序啟用,便無法停用。

在非 Windows 平臺上,如果 options.detached 設定為 true,子程序將成為新程序組和會話的領導者。無論是否分離,子程序都可以在父程序退出後繼續執行。更多資訊請參見 setsid(2)

預設情況下,父程序將等待分離的子程序退出。要防止父程序等待給定的 subprocess 退出,請使用 subprocess.unref() 方法。這樣做將導致父程序的事件迴圈不將子程序包含在其引用計數中,從而允許父程序獨立於子程序退出,除非子程序和父程序之間建立了 IPC 通道。

當使用 detached 選項啟動一個長時間執行的程序時,除非為其提供一個未連線到父程序的 stdio 配置,否則該程序在父程序退出後不會在後臺繼續執行。如果繼承了父程序的 stdio,子程序將保持附加到控制終端。

一個長時間執行程序的示例,透過分離並忽略其父程序的 stdio 檔案描述符,以忽略父程序的終止:

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();

或者,可以將子程序的輸出重定向到檔案中:

const { openSync } = require('node:fs');
const { spawn } = require('node:child_process');
const out = openSync('./out.log', 'a');
const err = openSync('./out.log', 'a');

const subprocess = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ],
});

subprocess.unref();import { openSync } from 'node:fs';
import { spawn } from 'node:child_process';
const out = openSync('./out.log', 'a');
const err = openSync('./out.log', 'a');

const subprocess = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ],
});

subprocess.unref();
options.stdio#

options.stdio 選項用於配置在父程序和子程序之間建立的管道。預設情況下,子程序的 stdin、stdout 和 stderr 會被重定向到 ChildProcess 物件上相應的 subprocess.stdinsubprocess.stdoutsubprocess.stderr 流。這等同於將 options.stdio 設定為 ['pipe', 'pipe', 'pipe']

為方便起見,options.stdio 可以是以下字串之一:

  • 'pipe':等同於 ['pipe', 'pipe', 'pipe'] (預設值)
  • 'overlapped':等同於 ['overlapped', 'overlapped', 'overlapped']
  • 'ignore':等同於 ['ignore', 'ignore', 'ignore']
  • 'inherit':等同於 ['inherit', 'inherit', 'inherit'][0, 1, 2]

否則,options.stdio 的值是一個數組,其中每個索引對應於子程序中的一個 fd。fd 0、1 和 2 分別對應於 stdin、stdout 和 stderr。可以指定額外的 fd 以在父子程序之間建立額外的管道。該值為以下之一:

  1. 'pipe':在子程序和父程序之間建立一個管道。管道的父端作為 child_process 物件上的一個屬性,即 subprocess.stdio[fd],暴露給父程序。為 fd 0、1 和 2 建立的管道也分別作為 subprocess.stdinsubprocess.stdoutsubprocess.stderr 可用。這些不是真正的 Unix 管道,因此子程序不能透過其描述符檔案(例如 /dev/fd/2/dev/stdout)來使用它們。

  2. 'overlapped':與 'pipe' 相同,只是在控制代碼上設定了 FILE_FLAG_OVERLAPPED 標誌。這對於子程序的 stdio 控制代碼上的重疊 I/O 是必需的。更多詳情請參閱文件。在非 Windows 系統上,這與 'pipe' 完全相同。

  3. 'ipc':建立一個 IPC 通道,用於在父子程序間傳遞訊息/檔案描述符。一個 ChildProcess 最多隻能有一個 IPC stdio 檔案描述符。設定此選項會啟用 subprocess.send() 方法。如果子程序是一個 Node.js 例項,IPC 通道的存在將啟用 process.send()process.disconnect() 方法,以及子程序內的 'disconnect''message' 事件。

    不支援以 process.send() 以外的任何方式訪問 IPC 通道 fd,或將 IPC 通道用於非 Node.js 例項的子程序。

  4. 'ignore':指示 Node.js 忽略子程序中的 fd。雖然 Node.js 總是為其衍生的程序開啟 fd 0、1 和 2,但將 fd 設定為 'ignore' 會導致 Node.js 開啟 /dev/null 並將其附加到子程序的 fd 上。

  5. 'inherit':將相應的 stdio 流傳遞給/從父程序。在前三個位置,這分別等同於 process.stdinprocess.stdoutprocess.stderr。在任何其他位置,等同於 'ignore'

  6. <Stream> 物件:與子程序共享一個可讀或可寫的流,該流引用一個 tty、檔案、套接字或管道。該流的底層檔案描述符在子程序中被複制到與 stdio 陣列中索引對應的 fd。該流必須有一個底層描述符(檔案流直到 'open' 事件發生後才開始)。注意: 雖然技術上可以將 stdin 作為可寫流或 stdout/stderr 作為可讀流傳遞,但不建議這樣做。可讀流和可寫流設計有不同的行為,不正確地使用它們(例如,在需要可寫流的地方傳遞可讀流)可能導致意外結果或錯誤。不鼓勵這種做法,因為它可能導致未定義的行為或在流遇到錯誤時丟失回撥。始終確保 stdin 作為可讀流使用,stdout/stderr 作為可寫流使用,以維持父子程序之間資料的預期流動。

  7. 正整數:該整數值被解釋為在父程序中開啟的檔案描述符。它與子程序共享,類似於 <Stream> 物件的共享方式。在 Windows 上不支援傳遞套接字。

  8. nullundefined:使用預設值。對於 stdio fd 0、1 和 2(即 stdin、stdout 和 stderr),會建立一個管道。對於 fd 3 及以上,預設為 'ignore'

const { spawn } = require('node:child_process');
const process = require('node:process');

// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr.
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });import { spawn } from 'node:child_process';
import process from 'node:process';

// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr.
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });

值得注意的是,當父子程序之間建立 IPC 通道,並且子程序是一個 Node.js 例項時,子程序啟動時 IPC 通道是未引用的(使用 unref()),直到子程序為 'disconnect' 事件或 'message' 事件註冊事件處理程式。這允許子程序正常退出,而不會因為開啟的 IPC 通道而使程序保持開啟狀態。 另見:child_process.exec()child_process.fork()

同步程序建立#

child_process.spawnSync()child_process.execSync()child_process.execFileSync() 方法是同步的,會阻塞 Node.js 事件迴圈,暫停執行任何其他程式碼,直到衍生的程序退出。

這類阻塞呼叫主要用於簡化通用指令碼任務和簡化啟動時應用程式配置的載入/處理。

child_process.execFileSync(file[, args][, options])#

  • file <string> 要執行的可執行檔案的名稱或路徑。
  • args <string[]> 字串引數列表。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 將作為 stdin 傳遞給衍生程序的值。如果 stdio[0] 設定為 'pipe',提供此值將覆蓋 stdio[0]
    • stdio <string> | <Array> 子程序的 stdio 配置。參見 child_process.spawn()stdio。預設情況下,stderr 將輸出到父程序的 stderr,除非指定了 stdio預設值: 'pipe'
    • env <Object> 環境變數鍵值對。預設值: process.env
    • uid <number> 設定程序的使用者標識(參見 setuid(2))。
    • gid <number> 設定程序的組標識(參見 setgid(2))。
    • timeout <number> 程序被允許執行的最長時間(以毫秒為單位)。預設值: undefined
    • killSignal <string> | <integer> 當衍生的程序被殺死時將使用的訊號值。預設值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允許的最大資料量(以位元組為單位)。如果超出,子程序將被終止。請參閱 maxBuffer 與 Unicode 中的注意事項。預設值: 1024 * 1024
    • encoding <string> 用於所有 stdio 輸入和輸出的編碼。預設值: 'buffer'
    • windowsHide <boolean> 隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值: false
    • shell <boolean> | <string> 如果為 true,則在 shell 中執行 command。在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。可以指定一個不同的 shell 作為字串。請參閱Shell 要求預設 Windows shell預設值: false (無 shell)。
  • 返回:<Buffer> | <string> 來自命令的 stdout。

child_process.execFileSync() 方法通常與 child_process.execFile() 相同,不同之處在於該方法在子程序完全關閉之前不會返回。當遇到超時併發送 killSignal 時,該方法在程序完全退出之前不會返回。

如果子程序攔截並處理了 SIGTERM 訊號但沒有退出,父程序仍將等待直到子程序退出。

如果程序超時或退出碼非零,此方法將丟擲一個 Error,其中將包含底層 child_process.spawnSync() 的完整結果。

如果啟用了 shell 選項,切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

const { execFileSync } = require('node:child_process');

try {
  const stdout = execFileSync('my-script.sh', ['my-arg'], {
    // Capture stdout and stderr from child process. Overrides the
    // default behavior of streaming child stderr to the parent stderr
    stdio: 'pipe',

    // Use utf8 encoding for stdio pipes
    encoding: 'utf8',
  });

  console.log(stdout);
} catch (err) {
  if (err.code) {
    // Spawning child process failed
    console.error(err.code);
  } else {
    // Child was spawned but exited with non-zero exit code
    // Error contains any stdout and stderr from the child
    const { stdout, stderr } = err;

    console.error({ stdout, stderr });
  }
}import { execFileSync } from 'node:child_process';

try {
  const stdout = execFileSync('my-script.sh', ['my-arg'], {
    // Capture stdout and stderr from child process. Overrides the
    // default behavior of streaming child stderr to the parent stderr
    stdio: 'pipe',

    // Use utf8 encoding for stdio pipes
    encoding: 'utf8',
  });

  console.log(stdout);
} catch (err) {
  if (err.code) {
    // Spawning child process failed
    console.error(err.code);
  } else {
    // Child was spawned but exited with non-zero exit code
    // Error contains any stdout and stderr from the child
    const { stdout, stderr } = err;

    console.error({ stdout, stderr });
  }
}

child_process.execSync(command[, options])#

  • command <string> 要執行的命令。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 將作為 stdin 傳遞給衍生程序的值。如果 stdio[0] 設定為 'pipe',提供此值將覆蓋 stdio[0]
    • stdio <string> | <Array> 子程序的 stdio 配置。參見 child_process.spawn()stdio。預設情況下,stderr 將輸出到父程序的 stderr,除非指定了 stdio預設值: 'pipe'
    • env <Object> 環境變數鍵值對。預設值: process.env
    • shell <string> 用於執行命令的 shell。參見Shell 要求預設 Windows shell預設值: Unix 上是 '/bin/sh',Windows 上是 process.env.ComSpec
    • uid <number> 設定程序的使用者標識。(參見 setuid(2))。
    • gid <number> 設定程序的組標識。(參見 setgid(2))。
    • timeout <number> 程序被允許執行的最長時間(以毫秒為單位)。預設值: undefined
    • killSignal <string> | <integer> 當衍生的程序被殺死時將使用的訊號值。預設值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允許的最大資料量(以位元組為單位)。如果超出,子程序將被終止,任何輸出都將被截斷。請參閱 maxBuffer 與 Unicode 中的注意事項。預設值: 1024 * 1024
    • encoding <string> 用於所有 stdio 輸入和輸出的編碼。預設值: 'buffer'
    • windowsHide <boolean> 隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值: false
  • 返回:<Buffer> | <string> 來自命令的 stdout。

child_process.execSync() 方法通常與 child_process.exec() 相同,不同之處在於該方法在子程序完全關閉之前不會返回。當遇到超時併發送 killSignal 時,該方法在程序完全退出之前不會返回。如果子程序攔截並處理了 SIGTERM 訊號但沒有退出,父程序將等待直到子程序退出。

如果程序超時或退出碼非零,此方法將丟擲異常。該 Error 物件將包含來自 child_process.spawnSync() 的完整結果。

切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

child_process.spawnSync(command[, args][, options])#

  • command <string> 要執行的命令。
  • args <string[]> 字串引數列表。
  • options <Object>
    • cwd <string> | <URL> 子程序的當前工作目錄。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 將作為 stdin 傳遞給衍生程序的值。如果 stdio[0] 設定為 'pipe',提供此值將覆蓋 stdio[0]
    • argv0 <string> 顯式設定傳送給子程序的 argv[0] 的值。如果未指定,將設定為 command
    • stdio <string> | <Array> 子程序的 stdio 配置。參見 child_process.spawn()stdio預設值: 'pipe'
    • env <Object> 環境變數鍵值對。預設值: process.env
    • uid <number> 設定程序的使用者標識(參見 setuid(2))。
    • gid <number> 設定程序的組標識(參見 setgid(2))。
    • timeout <number> 程序被允許執行的最長時間(以毫秒為單位)。預設值: undefined
    • killSignal <string> | <integer> 當衍生的程序被殺死時將使用的訊號值。預設值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允許的最大資料量(以位元組為單位)。如果超出,子程序將被終止,任何輸出都將被截斷。請參閱 maxBuffer 與 Unicode 中的注意事項。預設值: 1024 * 1024
    • encoding <string> 用於所有 stdio 輸入和輸出的編碼。預設值: 'buffer'
    • shell <boolean> | <string> 如果為 true,則在 shell 中執行 command。在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。可以指定一個不同的 shell 作為字串。請參閱Shell 要求預設 Windows shell預設值: false (無 shell)。
    • windowsVerbatimArguments <boolean> 在 Windows 上不對引數進行引用或轉義。在 Unix 上被忽略。當指定 shell 並且是 CMD 時,此選項會自動設定為 true預設值: false
    • windowsHide <boolean> 隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值: false
  • 返回:<Object>
    • pid <number> 子程序的 Pid。
    • output <Array> 來自 stdio 輸出的結果陣列。
    • stdout <Buffer> | <string> output[1] 的內容。
    • stderr <Buffer> | <string> output[2] 的內容。
    • status <number> | <null> 子程序的退出碼,如果子程序因訊號終止則為 null
    • signal <string> | <null> 用於殺死子程序的訊號,如果子程序不是因訊號終止則為 null
    • error <Error> 如果子程序失敗或超時,則為錯誤物件。

child_process.spawnSync() 方法通常與 child_process.spawn() 相同,不同之處在於該函式在子程序完全關閉之前不會返回。當遇到超時併發送 killSignal 時,該方法在程序完全退出之前不會返回。如果程序攔截並處理了 SIGTERM 訊號但沒有退出,父程序將等待直到子程序退出。

如果啟用了 shell 選項,切勿將未經處理的使用者輸入傳遞給此函式。任何包含 shell 元字元的輸入都可能被用於觸發任意命令執行。

類:ChildProcess#

ChildProcess 的例項代表衍生的子程序。

ChildProcess 的例項不應直接建立。相反,應使用 child_process.spawn()child_process.exec()child_process.execFile()child_process.fork() 方法來建立 ChildProcess 的例項。

事件:'close'#

  • code <number> 如果子程序自行退出,則為退出碼;如果子程序因訊號終止,則為 null
  • signal <string> 子程序被終止時所用的訊號;如果子程序不是因訊號終止,則為 null

'close' 事件在一個程序結束後並且子程序的 stdio 流被關閉後發出。這與 'exit' 事件不同,因為多個程序可能共享相同的 stdio 流。'close' 事件總是在 'exit' 事件已經發出之後,或者在子程序衍生失敗時在 'error' 事件之後發出。

如果程序已退出,code 是程序的最終退出碼,否則為 null。如果程序因接收到訊號而終止,signal 是訊號的字串名稱,否則為 null。兩者中總有一個是非 null

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

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

ls.on('close', (code) => {
  console.log(`child process close all stdio with code ${code}`);
});

ls.on('exit', (code) => {
  console.log(`child process exited with code ${code}`);
});import { spawn } from 'node:child_process';
const ls = spawn('ls', ['-lh', '/usr']);

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

ls.on('close', (code) => {
  console.log(`child process close all stdio with code ${code}`);
});

ls.on('exit', (code) => {
  console.log(`child process exited with code ${code}`);
});

事件:'disconnect'#

在父程序中呼叫 subprocess.disconnect() 方法或在子程序中呼叫 process.disconnect() 後,會發出 'disconnect' 事件。斷開連線後,不再可能傳送或接收訊息,並且 subprocess.connected 屬性為 false

事件:'error'#

'error' 事件在以下情況時發出:

  • 無法衍生該程序。
  • 無法殺死該程序。
  • 向子程序傳送訊息失敗。
  • 子程序透過 signal 選項被中止。

發生錯誤後,'exit' 事件可能會也可能不會觸發。當同時監聽 'exit''error' 事件時,要防止意外地多次呼叫處理函式。

另請參見 subprocess.kill()subprocess.send()

事件:'exit'#

  • code <number> 如果子程序自行退出,則為退出碼;如果子程序因訊號終止,則為 null
  • signal <string> 子程序被終止時所用的訊號;如果子程序不是因訊號終止,則為 null

'exit' 事件在子程序結束後發出。如果程序已退出,code 是程序的最終退出碼,否則為 null。如果程序因接收到訊號而終止,signal 是訊號的字串名稱,否則為 null。兩者中總有一個是非 null

'exit' 事件觸發時,子程序的 stdio 流可能仍然是開啟的。

Node.js 為 SIGINTSIGTERM 建立了訊號處理程式,因此 Node.js 程序不會因為接收到這些訊號而立即終止。相反,Node.js 將執行一系列清理操作,然後重新引發被處理的訊號。

參見 waitpid(2)

事件:'message'#

當子程序使用 process.send() 傳送訊息時,會觸發 'message' 事件。

訊息會經過序列化和解析。最終的訊息可能與最初發送的不同。

如果在衍生子程序時將 serialization 選項設定為 'advanced',則 message 引數可以包含 JSON 無法表示的資料。更多詳情請參見高階序列化

事件:'spawn'#

'spawn' 事件在子程序成功衍生後立即發出。如果子程序未能成功衍生,則不會發出 'spawn' 事件,而是會發出 'error' 事件。

如果發出,'spawn' 事件會先於所有其他事件,並且在透過 stdoutstderr 接收到任何資料之前發生。

無論在衍生的程序內部是否發生錯誤,'spawn' 事件都會觸發。例如,如果 bash some-command 成功衍生,'spawn' 事件會觸發,即使 bash 可能未能衍生 some-command。這個注意事項也適用於使用 { shell: true } 的情況。

subprocess.channel#

  • 型別:<Object> 代表到子程序的 IPC 通道的管道。

subprocess.channel 屬性是對子程序 IPC 通道的引用。如果不存在 IPC 通道,則此屬性為 undefined

subprocess.channel.ref()#

如果之前呼叫了 .unref(),此方法會使 IPC 通道保持父程序的事件迴圈執行。

subprocess.channel.unref()#

此方法使 IPC 通道不保持父程序的事件迴圈執行,並允許其在通道仍然開啟時完成。

subprocess.connected#

  • 型別:<boolean> 在呼叫 subprocess.disconnect() 後設置為 false

subprocess.connected 屬性指示是否仍然可以從子程序傳送和接收訊息。當 subprocess.connectedfalse 時,不再可能傳送或接收訊息。

subprocess.disconnect()#

關閉父子程序之間的 IPC 通道,允許子程序在沒有其他連線使其保持活動狀態時正常退出。呼叫此方法後,父程序和子程序(分別為)中的 subprocess.connectedprocess.connected 屬性將設定為 false,並且將不再可能在程序之間傳遞訊息。

當沒有正在接收的訊息時,將發出 'disconnect' 事件。這通常會在呼叫 subprocess.disconnect() 後立即觸發。

當子程序是 Node.js 例項時(例如,使用 child_process.fork() 衍生),可以在子程序內部呼叫 process.disconnect() 方法來關閉 IPC 通道。

subprocess.exitCode#

subprocess.exitCode 屬性表示子程序的退出碼。如果子程序仍在執行,該欄位將為 null

subprocess.kill([signal])#

subprocess.kill() 方法向子程序傳送一個訊號。如果沒有提供引數,程序將被髮送 'SIGTERM' 訊號。有關可用訊號的列表,請參見 signal(7)。如果 kill(2) 成功,此函式返回 true,否則返回 false

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP');import { spawn } from 'node:child_process';
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP');

如果訊號無法傳遞,ChildProcess 物件可能會發出一個 'error' 事件。向一個已經退出的子程序傳送訊號不是錯誤,但可能會產生不可預見的後果。具體來說,如果程序識別符號(PID)已被重新分配給另一個程序,訊號將被傳遞給那個程序,這可能會產生意想不到的結果。

雖然該函式名為 kill,但傳遞給子程序的訊號可能實際上不會終止該程序。

請參閱 kill(2) 以供參考。

在 Windows 上,由於不存在 POSIX 訊號,signal 引數將被忽略,除了 'SIGKILL''SIGTERM''SIGINT''SIGQUIT',程序將總是被強制和突然地殺死(類似於 'SIGKILL')。更多詳情請參見訊號事件

在 Linux 上,當試圖殺死父程序時,子程序的子程序不會被終止。當在 shell 中執行新程序或使用 ChildProcessshell 選項時,很可能會發生這種情況。

const { spawn } = require('node:child_process');

const subprocess = spawn(
  'sh',
  [
    '-c',
    `node -e "setInterval(() => {
      console.log(process.pid, 'is alive')
    }, 500);"`,
  ], {
    stdio: ['inherit', 'inherit', 'inherit'],
  },
);

setTimeout(() => {
  subprocess.kill(); // Does not terminate the Node.js process in the shell.
}, 2000);import { spawn } from 'node:child_process';

const subprocess = spawn(
  'sh',
  [
    '-c',
    `node -e "setInterval(() => {
      console.log(process.pid, 'is alive')
    }, 500);"`,
  ], {
    stdio: ['inherit', 'inherit', 'inherit'],
  },
);

setTimeout(() => {
  subprocess.kill(); // Does not terminate the Node.js process in the shell.
}, 2000);

subprocess[Symbol.dispose]()#

使用 'SIGTERM' 呼叫 subprocess.kill()

subprocess.killed#

  • 型別:<boolean> 在使用 subprocess.kill() 成功向子程序傳送訊號後設置為 true

subprocess.killed 屬性指示子程序是否成功從 subprocess.kill() 接收到訊號。killed 屬性並不表示子程序已被終止。

subprocess.pid#

返回子程序的程序識別符號(PID)。如果子程序因錯誤未能衍生,則該值為 undefined 併發出 error

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

console.log(`Spawned child pid: ${grep.pid}`);
grep.stdin.end();import { spawn } from 'node:child_process';
const grep = spawn('grep', ['ssh']);

console.log(`Spawned child pid: ${grep.pid}`);
grep.stdin.end();

subprocess.ref()#

在呼叫 subprocess.unref() 後再呼叫 subprocess.ref(),將恢復被移除的子程序引用計數,強制父程序在自己退出前等待子程序退出。

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();
subprocess.ref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();
subprocess.ref();

subprocess.send(message[, sendHandle[, options]][, callback])#

  • message <Object>
  • sendHandle <Handle> | <undefined> undefined,或者一個 net.Socketnet.Serverdgram.Socket 物件。
  • options <Object> options 引數(如果存在)是一個用於引數化傳送某些型別控制代碼的物件。options 支援以下屬性:
    • keepOpen <boolean> 一個可以在傳遞 net.Socket 例項時使用的值。當為 true 時,套接字在傳送程序中保持開啟狀態。預設值: false
  • callback <Function>
  • 返回:<boolean>

當父子程序之間建立了 IPC 通道時(即,當使用 child_process.fork() 時),可以使用 subprocess.send() 方法向子程序傳送訊息。當子程序是 Node.js 例項時,這些訊息可以透過 'message' 事件接收。

訊息會經過序列化和解析。最終的訊息可能與最初發送的不同。

例如,在父指令碼中:

const { fork } = require('node:child_process');
const forkedProcess = fork(`${__dirname}/sub.js`);

forkedProcess.on('message', (message) => {
  console.log('PARENT got message:', message);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
forkedProcess.send({ hello: 'world' });import { fork } from 'node:child_process';
const forkedProcess = fork(`${import.meta.dirname}/sub.js`);

forkedProcess.on('message', (message) => {
  console.log('PARENT got message:', message);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
forkedProcess.send({ hello: 'world' });

然後子指令碼 'sub.js' 可能看起來像這樣:

process.on('message', (message) => {
  console.log('CHILD got message:', message);
});

// Causes the parent to print: PARENT got message: { foo: 'bar', baz: null }
process.send({ foo: 'bar', baz: NaN }); 

子 Node.js 程序將有自己的 process.send() 方法,允許子程序向父程序傳送回訊息。

傳送 {cmd: 'NODE_foo'} 訊息時有一個特殊情況。cmd 屬性中包含 NODE_ 字首的訊息是為 Node.js 核心內部使用而保留的,不會在子程序的 'message' 事件中發出。相反,此類訊息使用 'internalMessage' 事件發出,並由 Node.js 內部消費。應用程式應避免使用此類訊息或監聽 'internalMessage' 事件,因為它可能會在沒有通知的情況下更改。

可以傳遞給 subprocess.send() 的可選 sendHandle 引數用於將 TCP 伺服器或套接字物件傳遞給子程序。子程序將收到的物件作為傳遞給在 'message' 事件上註冊的回撥函式的第二個引數。在套接字中接收和緩衝的任何資料都不會發送給子程序。在 Windows 上不支援傳送 IPC 套接字。

可選的 callback 是一個在訊息傳送後、但在子程序可能收到它之前呼叫的函式。該函式以單個引數呼叫:成功時為 null,失敗時為 Error 物件。

如果沒有提供 callback 函式且訊息無法傳送,ChildProcess 物件將發出一個 'error' 事件。例如,當子程序已經退出時,可能會發生這種情況。

如果通道已關閉,或者未傳送訊息的積壓超過了不宜再發送的閾值,subprocess.send() 將返回 false。否則,該方法返回 truecallback 函式可用於實現流量控制。

示例:傳送一個 server 物件#

sendHandle 引數可以用於,例如,將 TCP 伺服器物件的控制代碼傳遞給子程序,如下例所示:

const { fork } = require('node:child_process');
const { createServer } = require('node:net');

const subprocess = fork('subprocess.js');

// Open up the server object and send the handle.
const server = createServer();
server.on('connection', (socket) => {
  socket.end('handled by parent');
});
server.listen(1337, () => {
  subprocess.send('server', server);
});import { fork } from 'node:child_process';
import { createServer } from 'node:net';

const subprocess = fork('subprocess.js');

// Open up the server object and send the handle.
const server = createServer();
server.on('connection', (socket) => {
  socket.end('handled by parent');
});
server.listen(1337, () => {
  subprocess.send('server', server);
});

子程序將接收到伺服器物件,如下所示:

process.on('message', (m, server) => {
  if (m === 'server') {
    server.on('connection', (socket) => {
      socket.end('handled by child');
    });
  }
}); 

一旦伺服器在父子程序之間共享,一些連線可以由父程序處理,一些由子程序處理。

雖然上面的例子使用了 node:net 模組建立的伺服器,但 node:dgram 模組的伺服器使用完全相同的工作流程,除了監聽 'message' 事件而不是 'connection',以及使用 server.bind() 而不是 server.listen()。然而,這隻在 Unix 平臺上受支援。

示例:傳送一個 socket 物件#

類似地,sendHandler 引數可用於將套接字的控制代碼傳遞給子程序。下面的例子衍生了兩個子程序,每個子程序處理“正常”或“特殊”優先順序的連線:

const { fork } = require('node:child_process');
const { createServer } = require('node:net');

const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Open up the server and send sockets to child. Use pauseOnConnect to prevent
// the sockets from being read before they are sent to the child process.
const server = createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

  // If this is special priority...
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // This is normal priority.
  normal.send('socket', socket);
});
server.listen(1337);import { fork } from 'node:child_process';
import { createServer } from 'node:net';

const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Open up the server and send sockets to child. Use pauseOnConnect to prevent
// the sockets from being read before they are sent to the child process.
const server = createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

  // If this is special priority...
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // This is normal priority.
  normal.send('socket', socket);
});
server.listen(1337);

subprocess.js 將收到套接字控制代碼作為傳遞給事件回撥函式的第二個引數:

process.on('message', (m, socket) => {
  if (m === 'socket') {
    if (socket) {
      // Check that the client socket exists.
      // It is possible for the socket to be closed between the time it is
      // sent and the time it is received in the child process.
      socket.end(`Request handled with ${process.argv[2]} priority`);
    }
  }
}); 

不要在已傳遞給子程序的套接字上使用 .maxConnections。父程序無法跟蹤套接字何時被銷燬。

子程序中的任何 'message' 處理程式都應驗證 socket 是否存在,因為在將連線傳送給子程序期間,連線可能已經關閉。

subprocess.signalCode#

subprocess.signalCode 屬性表示子程序收到的訊號(如果有),否則為 null

subprocess.spawnargs#

subprocess.spawnargs 屬性表示子程序啟動時使用的完整命令列引數列表。

subprocess.spawnfile#

subprocess.spawnfile 屬性表示啟動的子程序的可執行檔名。

對於 child_process.fork(),其值將等於 process.execPath。對於 child_process.spawn(),其值將是可執行檔案的名稱。對於 child_process.exec(),其值將是啟動子程序的 shell 的名稱。

subprocess.stderr#

一個代表子程序 stderrReadable Stream

如果子程序衍生時 stdio[2] 設定為除 'pipe' 之外的任何值,則此值為 null

subprocess.stderrsubprocess.stdio[2] 的別名。兩個屬性都將引用相同的值。

如果子程序無法成功衍生,subprocess.stderr 屬性可能為 nullundefined

subprocess.stdin#

一個代表子程序 stdinWritable Stream

如果子程序等待讀取其所有輸入,則子程序將不會繼續,直到此流透過 end() 關閉。

如果子程序衍生時 stdio[0] 設定為除 'pipe' 之外的任何值,則此值為 null

subprocess.stdinsubprocess.stdio[0] 的別名。兩個屬性都將引用相同的值。

如果子程序無法成功衍生,subprocess.stdin 屬性可能為 nullundefined

subprocess.stdio#

一個到子程序的稀疏管道陣列,對應於傳遞給 child_process.spawn()stdio 選項中已設定為 'pipe' 值的位置。subprocess.stdio[0]subprocess.stdio[1]subprocess.stdio[2] 也分別作為 subprocess.stdinsubprocess.stdoutsubprocess.stderr 可用。

在以下示例中,只有子程序的 fd 1 (stdout) 被配置為管道,因此只有父程序的 subprocess.stdio[1] 是一個流,陣列中的所有其他值均為 null

const assert = require('node:assert');
const fs = require('node:fs');
const child_process = require('node:child_process');

const subprocess = child_process.spawn('ls', {
  stdio: [
    0, // Use parent's stdin for child.
    'pipe', // Pipe child's stdout to parent.
    fs.openSync('err.out', 'w'), // Direct child's stderr to a file.
  ],
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);import assert from 'node:assert';
import fs from 'node:fs';
import child_process from 'node:child_process';

const subprocess = child_process.spawn('ls', {
  stdio: [
    0, // Use parent's stdin for child.
    'pipe', // Pipe child's stdout to parent.
    fs.openSync('err.out', 'w'), // Direct child's stderr to a file.
  ],
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);

如果子程序無法成功衍生,subprocess.stdio 屬性可能為 undefined

subprocess.stdout#

一個代表子程序 stdoutReadable Stream

如果子程序衍生時 stdio[1] 設定為除 'pipe' 之外的任何值,則此值為 null

subprocess.stdoutsubprocess.stdio[1] 的別名。兩個屬性都將引用相同的值。

const { spawn } = require('node:child_process');

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
  console.log(`Received chunk ${data}`);
});import { spawn } from 'node:child_process';

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
  console.log(`Received chunk ${data}`);
});

如果子程序無法成功衍生,subprocess.stdout 屬性可能為 nullundefined

subprocess.unref()#

預設情況下,父程序將等待分離的子程序退出。要防止父程序等待給定的 subprocess 退出,請使用 subprocess.unref() 方法。這樣做將導致父程序的事件迴圈不將子程序包含在其引用計數中,允許父程序獨立於子程序退出,除非在子程序和父程序之間建立了 IPC 通道。

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();

maxBuffer 與 Unicode#

maxBuffer 選項指定 stdoutstderr 上允許的最大位元組數。如果超過此值,則子程序將被終止。這會影響包含多位元組字元編碼(如 UTF-8 或 UTF-16)的輸出。例如,console.log('中文測試') 將向 stdout 傳送 13 個 UTF-8 編碼的位元組,儘管只有 4 個字元。

Shell 要求#

Shell 應該理解 -c 開關。如果 shell 是 'cmd.exe',它應該理解 /d /s /c 開關,並且命令列解析應該相容。

預設的 Windows shell#

儘管微軟規定 %COMSPEC% 必須在根環境中包含到 'cmd.exe' 的路徑,但子程序並不總是受此要求的約束。因此,在可以衍生 shell 的 child_process 函式中,如果 process.env.ComSpec 不可用,則使用 'cmd.exe' 作為後備。

高階序列化#

子程序支援一種用於 IPC 的序列化機制,該機制基於 node:v8 模組的序列化 API,並基於 HTML 結構化克隆演算法。這通常功能更強大,並支援更多內建的 JavaScript 物件型別,如 BigIntMapSetArrayBufferTypedArrayBufferErrorRegExp 等。

然而,此格式並非 JSON 的完全超集,例如,在這些內建型別物件上設定的屬性不會在序列化步驟中傳遞。此外,根據傳遞資料的結構,其效能可能與 JSON 不等。因此,此功能需要在呼叫 child_process.spawn()child_process.fork() 時,透過將 serialization 選項設定為 'advanced' 來選擇性啟用。