用于asynchronousLinux脚本的Node.js

在我写的其他程序中,我使用promise来享受node.js的asynchronous方面。

我想为Linux脚本使用相同的编程风格(使用node.js)。 换句话说,我希望能够同时执行多个Linux命令,然后在这些命令完成之后,我希望node.js脚本asynchronous执行另一组命令(如果没有阻塞)。

我遇到了一个aritlce ,它展示了如何使用node.js执行同步Linux命令,但是我还没有find类似的教程,其中涵盖了使用node.jspipe理多个asynchronousLinux命令。

目前这是可能的吗? 如果是这样,你能指示我一些具体的资源,可以帮助我开始这个目标吗?

我不确定我是否正确,但我认为你正在寻找execspawn 。 请参阅相关的API文档 。 文档中有两个命令的例子。

execspawn

execspawn的“简单”版本。 前者使用单个callback函数在命令完成时向用户报告,并且仅在完成/失败时才报告给用户。

 child = exec('cat *.js bad_file | wc -l', function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } }); 

所以,基本上只有当被写入stdout / stderr的东西完全可用时才会调用提供的callback函数。 在程序终止(成功或失败)之后,只有这个callback被调用,用户(你)才能对它进行操作。 如果失败的error真的

spawn是不同的,因为你可以听stdout / stderr 事件 。 首先你“产生”一个过程。 spawn函数返回对subprocess的引用。

 var spawn = require('child_process').spawn; var ls = spawn('ls', ['-lh', '/usr']); 

这里是你产生的孩子过程。 它有两个属性(现在的重要性), stdoutstderr是事件发射器。 他们正在发送data事件。 当它被写入任何stream时,在data事件上注册的callback被调用。

 ls.stdout.on('data', function (data) { console.log('stdout: ' + data); }); ls.stderr.on('data', function (data) { console.log('stderr: ' + data); }); 

当然还有其他重要的事件(查看文档以获得当然最新和相关的信息)。

 ls.on('close', function (code) { console.log('child process exited with code ' + code); }); 

当你想在stdout上捕获东西的时候你会使用spawn ,例如当进程正在运行的时候。 一个很好的例子就是如果你产生了一个花费数分钟才能完成的ffmpeg编码任务。 你可以听stderr(因为ffmpeg把进度信息写到stderr而不是stdout)来parsing“进度”信息。

逐行与carrier

有一个很好的附加库可以和spawn一起使用。 这就是所谓的载体 。 它有助于从产生的进程的stdout / stderr中读取“行”。 这很有用,因为传递给callback函数的data参数不一定包含由\n分隔的“完整”行。 carrier帮助。 (但是,它不会帮助你捕获stderr上的ffmpeg进度,因为在这种情况下没有用ffmpeg写的换行符,它只是一个回车符,基本上这个行总是被重写。)

你会这样使用它

 var carry = require("carrier").carry; var child = spawn("command"); carry(child.stdout, function(line) { console.log("stdout", line); }); 

承诺和延期

如果你想使用承诺/延期风格的方法,那么你可以使用AngularJS 使用的Q来做类似以下的事情 – 或者至less是非常相似的东西(参见完整的承诺教程链接)。

spawn返回一个Emitter对象,这不是一个承诺。 所以你必须把调用包装成spawn( 请参阅使用延迟 )。

 var q = require("q"); var spawn = require("child_process").spawn; var ls = function() { var deferred = q.defer(); var ls = spawn("ls", ["-lh", "/usr"]); ls.stdout.on("data", function(data) { deferred.notify({stdout: true, data: data}); }); ls.stderr.on("data", function(data) { deferred.notify({stderr: true, data: data}); }); ls.on("close", function(code) { if (code === 0) { deferred.resolve(); } else { deferred.reject(code); } }); return deferred.promise; }; 

通过执行ls()现在可以返回一个承诺,您可以像其他承诺一样使用。 当它完全解决时,第一个callback被调用。 如果发生错误(进程存在非零退出代码),则调用error handling程序。 当命令进行时,第三个callback将被调用(通知callback)。

 ls().then(function() { console.log("child process exited successfully"); }, function(err) { console.log("child process exited with code " + err); }, function(args) { if (args.stdout) { console.log("stdout: " + args.data); } else { console.log("stderr: " + args.data); } }); 

当一些事情被写到stderr时,你可以立即调用拒绝,这是一个devise决定。 回到ffmpeg的例子,这不会对你有什么好处,因为ffmpeg将一般信息吐在stderr。 但是,它可以与其他命令一起使用。

我想你会得到它:)

例子来自nodejs的文档,因为它们很好理解。

在核心节点库中,同步函数将Sync附加到函数名称。 他们正在使用child_process.execFileSync ,所以你应该寻找child_process.execFileasynchronous版本的function。

我推荐一种结合了生成器和承诺的方法。 这是先决条件:

  • 使用--harmony标志或任何版本的io.js(不需要标志)节点0.11或更高。
  • 生成器处理程序。 这是我的最爱: https : //www.npmjs.com/package/co
  • 将Node的基于callback的方法转换为promise返回函数的一种方法。 我使用这个: https : //www.npmjs.com/package/ugly-adapter

然后做你想要的东西:

 var co = require('co'); var adapt = require('ugly-adapter'); var childProcessExec = require('child_process').exec; var exec = adapt.part(childProcessExec); co(function*() { // run commands in parallel by yielding // a single object or array var result = yield { listing: exec('ls -l'), mkdirResult: exec('mkdir foo'), blah: exec('echo "blah blah"'), }; console.log(result.blah); // "blah blah" // run commands in series by yielding // one thing at a time var listing = yield exec('ls -l'); var mkdirResult = yield exec('mkdir foo2'); var blah = yield exec('echo "blah blah"'); console.log(blah); // "blah blah" }).catch(function(err){ // this handles any possible errors // thrown by the above console.error(err.stack); process.exit(1); }); 

yield关键字会导致函数暂停,同时解开承诺并将结果发送回您的函数。 注意: library co实际上只是es7中的asynchronous/等待的暂时替身,其工作方式基本相同。