如何使用Bluebird对节点的child_process.exec和child_process.execFile函数进行promisify?

我在Node.js下使用蓝鸟承诺库,这太棒了! 但是我有一个问题:

如果查看Node的child_process.exec和child_process.execFile的文档,可以看到这两个函数都返回一个ChildProcess对象。

那么推荐这种function的推荐方式是什么?

请注意,以下作品(我得到一个Promise对象):

var Promise = require('bluebird'); var execAsync = Promise.promisify(require('child_process').exec); var execFileAsync = Promise.promisify(require('child_process').execFile); 

但是,如何获得原始的Node.js函数的原始返回值呢? (在这些情况下,我需要能够访问最初返回的ChildProcess对象。)

任何build议,将不胜感激!

编辑:

这是一个使用child_process.exec函数的返回值的示例代码:

 var exec = require('child_process').exec; var child = exec('node ./commands/server.js'); child.stdout.on('data', function(data) { console.log('stdout: ' + data); }); child.stderr.on('data', function(data) { console.log('stderr: ' + data); }); child.on('close', function(code) { console.log('closing code: ' + code); }); 

但是,如果我使用exec函数的promisified版本(从上面的execAsync),那么返回值将是一个承诺,而不是一个ChildProcess对象。 这是我正在谈论的真正的问题。

这听起来像你想从电话中返回两件事情:

  • 儿童进程
  • 在儿童进程完成时解决的承诺

那么“推荐这种function的推荐方式”呢? 不要

你超出了惯例。 Promise返回函数预计会返回一个承诺,就是这样。 你可以返回一个有两个成员的对象(ChildProcess和promise),但这只会让人们感到困惑。

我build议调用unpromisified函数,并根据返回的childProcess创build一个promise。 (也许包装成一个帮手function)

这样,读取代码的下一个人就很清楚了。

就像是:

 var Promise = require('bluebird'); var exec = require('child_process').execFile; function promiseFromChildProcess(child) { return new Promise(function (resolve, reject) { child.addListener("error", reject); child.addListener("exit", resolve); }); } var child = exec('ls'); promiseFromChildProcess(child).then(function (result) { console.log('promise complete: ' + result); }, function (err) { console.log('promise rejected: ' + err); }); child.stdout.on('data', function (data) { console.log('stdout: ' + data); }); child.stderr.on('data', function (data) { console.log('stderr: ' + data); }); child.on('close', function (code) { console.log('closing code: ' + code); }); 

可能没有办法很好地覆盖所有用例。 但是对于有限的情况,你可以这样做:

 /** * Promisified child_process.exec * * @param cmd * @param opts See child_process.exec node docs * @param {stream.Writable} opts.stdout If defined, child process stdout will be piped to it. * @param {stream.Writable} opts.stderr If defined, child process stderr will be piped to it. * * @returns {Promise<{ stdout: string, stderr: stderr }>} */ function execp(cmd, opts) { opts || (opts = {}); return new Promise((resolve, reject) => { const child = exec(cmd, opts, (err, stdout, stderr) => err ? reject(err) : resolve({ stdout: stdout, stderr: stderr })); if (opts.stdout) { child.stdout.pipe(opts.stdout); } if (opts.stderr) { child.stderr.pipe(opts.stderr); } }); } 

这接受opts.stdoutopts.stderr参数,以便可以从subprocess中捕获stdio。

例如:

 execp('ls ./', { stdout: new stream.Writable({ write: (chunk, enc, next) => { console.log(chunk.toString(enc)); next(); } }), stderr: new stream.Writable({ write: (chunk, enc, next) => { console.error(chunk.toString(enc)); next(); } }) }).then(() => console.log('done!')); 

或者干脆:

 execp('ls ./', { stdout: process.stdout, stderr: process.stderr }).then(() => console.log('done!')); 

只是想提一下,有一个很好的工具可以完全解决你的问题:

https://www.npmjs.com/package/core-worker

这个包使得处理过程变得更容易。

 import { process } from "CoreWorker"; import fs from "fs"; const result = await process("node Server.js", "Server is ready.").ready(1000); const result = await process("cp path/to/file /newLocation/newFile").death(); 

或者结合这些function:

 import { process } from "core-worker"; const simpleChat = process("node chat.js", "Chat ready"); setTimeout(() => simpleChat.kill(), 360000); // wait an hour and close the chat simpleChat.ready(500) .then(console.log.bind(console, "You are now able to send messages.")) .then(::simpleChat.death) .then(console.log.bind(console, "Chat closed")) .catch(() => /* handle err */);