Node.jsにおける子プロセス(Child Process)の管理は、バックグラウンドで重い処理を非同期で実行する場合に非常に重要な技術です。Node.jsはシングルスレッドで動作するため、CPU集中的なタスクを非同期に扱う必要があります。このため、子プロセスを利用することにより、メインスレッド(イベントループ)のブロックを避けつつ、別スレッドで重い処理を実行できます。本記事では、Node.jsでの子プロセスの作成、管理、活用方法について完全かつ包括的に解説します。
1. 子プロセスとは?
Node.jsの「子プロセス」は、外部プログラムやスクリプトを実行するためのプロセスであり、child_process
モジュールを利用して作成できます。これにより、Node.jsアプリケーションから外部のスクリプトやコマンドラインツールを呼び出し、その結果を処理することが可能になります。

Node.jsのchild_process
モジュールには、いくつかのメソッドがあり、プロセスを生成する際に異なる動作を選択できます。
2. child_process
モジュールの使用
Node.jsのchild_process
モジュールには、主に以下の4つのメソッドがあります:
exec()
spawn()
fork()
execFile()
これらのメソッドの使い方について、順を追って説明します。
2.1 exec()
exec()
は、シェルコマンドを実行するために使用されます。このメソッドは、コマンドの実行が終了するまで待機し、完了した後に標準出力または標準エラー出力を取得できます。
javascriptconst { exec } = require('child_process');
exec('ls', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
このコードは、ls
コマンドを実行して、その結果を表示します。
2.2 spawn()
spawn()
は、外部コマンドを実行する際に使われる最も一般的なメソッドです。spawn()
は、標準出力(stdout)や標準エラー出力(stderr)をストリームとして返し、これにより長時間実行されるコマンドを非同期に処理できます。
javascriptconst { spawn } = require('child_process');
const ls = spawn('ls', ['-l', '/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}`);
});
ここでは、spawn()
を使用して、ls -l /usr
というコマンドを実行し、その出力をリアルタイムで表示しています。
2.3 fork()
fork()
は、Node.jsのプロセスを別のNode.jsプロセスとして作成するメソッドです。主に、Node.jsアプリケーション内で別プロセスを立ち上げ、その間で通信を行いたい場合に使用されます。fork()
を使うと、プロセス間でメッセージをやり取りすることができます。
javascriptconst { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (message) => {
console.log(`Received message from child: ${message}`);
});
child.send('Hello from parent!');
child.js
というファイル内で、受け取ったメッセージを返すようにします。
child.js
:
javascriptprocess.on('message', (message) => {
console.log(`Received from parent: ${message}`);
process.send('Hello from child!');
});
このコードでは、親プロセスと子プロセス間でメッセージの送受信を行っています。
2.4 execFile()
execFile()
は、指定したファイル(スクリプトやプログラム)を実行するために使われます。exec()
とは異なり、シェルを介さずに直接ファイルを実行します。この方法は、セキュリティ上の理由からも推奨されることがあります。
javascriptconst { execFile } = require('child_process');
execFile('ls', ['-l', '/usr'], (error, stdout, stderr) => {
if (error) {
console.error(`execFile error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
if (stderr) {
console.error(`stderr: ${stderr}`);
}
});
このコードは、ls
コマンドを実行し、その結果を出力します。シェルを経由せずに、直接実行することが特徴です。
3. 子プロセスとの通信
子プロセスと親プロセス間でデータを交換するために、メッセージングを利用することができます。主にfork()
メソッドを使用した場合にメッセージングが有効です。send()
とmessage
イベントを使用することで、双方向の通信を行うことができます。
親プロセスから子プロセスへのメッセージ送信:
javascriptconst child = fork('child.js');
child.send('Hello, child!');
子プロセスから親プロセスへのメッセージ送信:
javascriptprocess.on('message', (msg) => {
console.log(`Message from parent: ${msg}`);
process.send('Hello, parent!');
});
このように、子プロセスと親プロセスの間で効率的なデータ交換が可能です。
4. 子プロセスの終了
子プロセスが終了した後、close
イベントが発生します。close
イベントは、子プロセスが正常に終了したか、エラーで終了したかにかかわらず発生します。
javascriptconst { spawn } = require('child_process');
const child = spawn('ls', ['-l']);
child.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
終了コードがゼロの場合は正常終了、ゼロ以外の場合は異常終了です。
5. エラーハンドリング
子プロセスを利用する際には、エラーハンドリングが重要です。stderr
イベントを利用することで、エラーが発生した場合に適切に対応できます。
javascriptconst { spawn } = require('child_process');
const child = spawn('nonexistentcommand');
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
エラーが発生した場合、その内容をstderr
から取得し、処理することができます。
6. まとめ
Node.jsにおける子プロセスの利用は、非同期処理やバックグラウンド処理を効率的に行うための強力なツールです。child_process
モジュールを使用することで、外部プログラムやスクリプトを実行し、必要に応じて結果を処理することができます。また、プロセス間でのメッセージ通信やエラーハンドリングも簡単に実現できるため、複雑なアプリケーションにおいても非常に有用です。