はじめに
Node.jsのコードにおいてchild_processモジュールを使用する機会があり、その中でもspawnを理解したいと思い、こちらの記事を記載しました。
child_processモジュールとは
Node.jsでサブプロセス(子プロセス)を作成し、メインのNode.jsプロセスから独立してコマンドやプログラムを実行するための機能を提供します。
child_process.spawn
こちらの公式ドキュメントに記載のある通り、child_process.spawnの書き方としては、child_process.spawn(command[, args][, options])というように、実行するコマンド、配列の中に引数、オプションの順番で記載します。
サンプルコード
const { spawn } = require("child_process");
const child = spawn(
"node",
[
"-e",
`
process.stdin.on('data', (data) => {
process.stdout.write(data.toString().toUpperCase());
});
`,
],
{ stdio: ["pipe", "pipe", "inherit"] }
);
child.stdin.write("Hello, child process!\n");
child.stdout.on("data", (data) => {
console.log(`Child process output: ${data}`);
});
このコードは、Node.js の child_process.spawn() を使用して、別の Node.js プロセスを生成し、親プロセス(メインのスクリプト)からデータを送信して、子プロセス(生成されたプロセス)で処理を行い、その結果を受け取る構成です。
このコードでの具体的な流れ
- 親プロセスが child.stdin.write() で子プロセスに "Hello, child process!\n" を送ります。
- 子プロセス内で process.stdin.on('data') が発火し、データを受け取ります。
- 受け取ったデータを toString().toUpperCase() で大文字に変換し、process.stdout.write() で子プロセスの標準出力に書き込みます。
- 親プロセスが child.stdout.on('data') で子プロセスの出力を監視し、大文字に変換された結果("HELLO, CHILD PROCESS!\n")を console.log() で表示します。
実行されるコマンドは「node」です。引数に「-e」があり、Node.js の -e オプションは、指定された文字列をそのまま実行できる短いスクリプトを指定するものです。
・process.stdin.on('data', (data) => {
process.stdout.write(data.toString().toUpperCase());
});
子プロセス内で、process.stdin.on('data') を使って標準入力からデータを受け取り、そのデータを大文字に変換し、process.stdout.write() で標準出力に書き出します。
process.stdin を使うと、ユーザーがターミナルやコマンドラインからプログラムに入力した内容を受け取れます。
・{ stdio: ["pipe", "pipe", "inherit"] }
spawn 関数の第三引数として stdio オプションが渡されています。これは、子プロセスの標準入力(stdin)、標準出力(stdout)、標準エラー出力(stderr)がどう扱われるかを指定しています。
"pipe": 子プロセスの stdin と stdout を親プロセスと接続します。
"inherit": 子プロセスの stderr は親プロセスの stderr に直接接続されます(親プロセスのコンソールにそのままエラーメッセージが表示される)。
・child.stdin.write("Hello, child process!\n");
child.stdin: これは子プロセスの標準入力ストリームです。write メソッドを使用して、子プロセスにデータを送信しています。ストリームであるという記述はこちらにあります。
・child.stdout:これは、子プロセスの標準出力ストリームを指します。子プロセスが出力するすべてのデータはここに送られます。
標準出力(stdout)をinheritに変更した場合
const { spawn } = require("child_process");
const child = spawn(
"node",
[
"-e",
`
process.stdin.on('data', (data) => {
process.stdout.write(data.toString().toUpperCase());
});
`,
],
// { stdio: ["pipe", "pipe", "inherit"] }
{ stdio: ["pipe", "inherit", "inherit"] }
);
child.stdin.write("Hello, child process!\n");
// child.stdout.on("data", (data) => {
// console.log(`Child process output: ${data}`);
// });
{ stdio: ["pipe", "inherit", "inherit"] }
とした場合は、子プロセスの標準出力は、親プロセスの標準出力に直接接続されます。つまり、子プロセスが標準出力にデータを出力すると、そのまま親プロセスのコンソールに表示されます。そのため、親プロセスでの処理が出来ないため、最後のchild.stdout.on...のコードは削除する必要があります。
まとめ
Node.jsのchild_processモジュールの挙動を具体的なコードを用いてまとめました。記事に残しておくことで自分が見直す場合にも役立ちますし、他の方の参考にもなれば幸いです。
Reference