用于asynchronousLinux脚本的Node.js
在我写的其他程序中,我使用promise来享受node.js的asynchronous方面。
我想为Linux脚本使用相同的编程风格(使用node.js)。 换句话说,我希望能够同时执行多个Linux命令,然后在这些命令完成之后,我希望node.js脚本asynchronous执行另一组命令(如果没有阻塞)。
我遇到了一个aritlce ,它展示了如何使用node.js执行同步Linux命令,但是我还没有find类似的教程,其中涵盖了使用node.jspipe理多个asynchronousLinux命令。
目前这是可能的吗? 如果是这样,你能指示我一些具体的资源,可以帮助我开始这个目标吗?
我不确定我是否正确,但我认为你正在寻找exec
和spawn
。 请参阅相关的API文档 。 文档中有两个命令的例子。
exec
和spawn
exec
是spawn
的“简单”版本。 前者使用单个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']);
这里是你产生的孩子过程。 它有两个属性(现在的重要性), stdout
和stderr
是事件发射器。 他们正在发送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/等待的暂时替身,其工作方式基本相同。