BluebirdでChild Processをプロミス化
Node.jsのchild_process.exec
とchild_process.execFile
をBluebirdでプロミス化する
Node.jsでは、外部コマンドを実行するためのchild_process.exec
とchild_process.execFile
メソッドが提供されています。しかし、これらのメソッドはコールバックスタイルで動作するため、非同期処理を扱う際に少し面倒です。
BluebirdはJavaScript用のプロミスライブラリで、非同期処理をより直感的かつエラー処理が容易にできるようサポートします。
プロミス化の例
const childProcess = require('child_process');
const Promise = require('bluebird');
// child_process.execをプロミス化
function promisifiedExec(command) {
return new Promise((resolve, reject) => {
childProcess.exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stder r });
}
});
});
}
// child_process.execFileをプロミス化
function promisifiedExecFile(file, args) {
return new Promise((resolve, reject) => {
childProcess.execFile(file, args, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stderr });
}
});
});
}
// 使用例
promisifiedExec('ls -la')
.then(result => {
console.log(result.stdout);
})
.catch(error => {
console.error(error);
});
promisifiedExecFile('node', ['script.js'])
.then(result => {
console.log(result.stdout);
})
.catch(error => {
console.error(error);
});
プロミス化のメリット
- 読みやすさ
コールバックスタイルよりもコードが読みやすくなります。 - エラー処理
catch
メソッドを使ってエラーを統一的に処理できます。 - チェーン化
プロミスを使用することで、複数の非同期操作をチェーン化して記述できるようになります。
const childProcess = require('child_process');
const Promise = require('bluebird');
// child_process.execをプロミス化
function promisifiedExec(command) {
return new Promise((resolve, reject) => {
childProcess.exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stder r });
}
});
});
}
// child_process.execFileをプロミス化
function promisifiedExecFile(file, args) {
return new Promise((resolve, reject) => {
childProcess.execFile(file, args, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stderr });
}
});
});
}
// 使用例
promisifiedExec('ls -la')
.then(result => {
console.log(result.stdout);
})
.catch(error => {
console.error(error);
});
promisifiedExecFile('node', ['script.js'])
.then(result => {
console.log(result.stdout);
})
.catch(error => {
console.error(error);
});
コード解説
- Node.jsモジュールをインポート
child_process
とbluebird
をインポートします。 - promisifiedExec関数
child_process.exec
をプロミス化します。Promise
コンストラクタを使用して新しいプロミスを作成します。child_process.exec
を実行し、コールバック関数内で結果を処理します。- エラーが発生した場合、
reject
でプロミスを拒否します。 - 成功した場合、
resolve
でプロミスを解決し、標準出力と標準エラー出力を返します。
- promisifiedExecFile関数
child_process.execFile
をプロミス化します。promisifiedExec
と同様の手法でプロミス化します。
- 使用例
プロミス化された関数を使用して、外部コマンドを実行します。.then
で成功時の処理を指定します。.catch
でエラー時の処理を指定します。
ES2015のPromise APIを使用する
ES2015以降、JavaScriptにネイティブのPromise APIが導入されました。これを使用することで、次のようにプロミス化することができます。
const childProcess = require('child_process');
function promisifiedExec(command) {
return new Promise((resolve, reject) => {
childProcess.exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve({ stdout, stder r });
}
});
});
}
// 以下同様
サードパーティライブラリを使用する
他にも、プロミス化を簡略化するサードパーティライブラリを使用することもできます。例えば、util.promisify
モジュールは、コールバックスタイルの関数をプロミス化するヘルパー関数を提供します。
const childProcess = require('child_process');
const { promisify } = require('util');
const promisifiedExec = promisify(childProcess.exec);
const promisifiedExecFile = promisify(childProcess.execFile);
async/awaitを使用する
ES2017から導入されたasync/await
構文を使用すると、プロミスをより同期的なコードのように記述することができます。
const childProcess = require('child_process');
const { promisify } = require('util');
const promisifiedExec = promisify(childProcess.exec);
async function runCommand() {
try {
const result = await promisifiedExec('ls -la');
console.log(result.stdout);
} catch (error) {
console.error(error);
}
}
runCommand();
選択基準
どの方法を使用するかは、プロジェクトの要件やチームの好みによって異なります。Bluebirdを使用すると、プロミスに関する豊富な機能とコミュニティサポートが得られます。ES2015のPromise APIはネイティブでサポートされているため、外部ライブラリを使用する必要がありません。サードパーティライブラリやasync/await
は簡潔なコードを書くことができます。
javascript node.js promise