在node.js中运行串行操作

时间:2010-12-05 04:30:17

标签: javascript callback node.js

我有一个异步函数,可以并行执行一些shell命令

require("fs").readdir("./", function (error, folders) { // asynched
    require("underscore")._(folders).each(function (folder, folderKey, folderList) { // asynched
    r("child_process").exec("ls ./" + folder, function(error, stdout, stderr) {
           console.log("Cant put it here") // Will be run after the first execution is completed
        })
        console.log("Cant put it here either") // Will be run immediately before any execution is completed
    })
    console.log("Cant put it here either") // Will be run immediately before any execution is completed
})

我希望在执行这些shell命令后执行但我无法弄清楚如何使用异步库执行此操作。这些shell命令是并行执行的,因此无法在执行所有命令之后注册执行的处理程序。

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

使用async.js库:https://github.com/caolan/async

var fs = require('fs');
var async = require('async');
var exec = require('child_process').exec;

fs.readdir("./", function (error, folders) {
    async.forEach(folders, function (folder, callback) {
        exec("ls ./" + folder, function (error, stdout, stderr) {
            callback();
        });
    },
    function (error) {
        // this is called after all shell commands are complete
    })
});

答案 1 :(得分:3)

更新

在您编辑问题以显示实际代码后,这应该有效:

var ps = require('child_process');
var fs = require('fs');
var _ = require("underscore");

function listDirectory(dir, callback) {
    fs.readdir(dir, function (error, folders) {

        // simply keep track on how many of the ls's have finished
        var count = folders.length, done = 0;
        _(folders).each(function (folder, folderKey, folderList) {
            ps.exec("ls ./" + folder, function(error, stdout, stderr) {
                console.log('one more done');
                done++;
                if (done === count) {
                    callback();
                } 
            });  
        });
    })
}

listDirectory('./', function() {
    console.log('all done!');
});

运行时:

one more done
one more done
one more done
one more done
one more done
one more done
one more done
one more done
one more done
one more done
one more done
one more done
all done!

旧答案

我想您使用的是child_process模块。

您需要围绕命令创建一个包装器。

var spawn = require('child_process').spawn;


// this function will execute all the things in the cmds array
// after all the processes have exited, it will call the callback
function multiSpawn(cmds, callback) {
    var count = cmds.length;
    var done = 0;
    for(var i = 0; i < count; i++) {
        // spawn the process, modify this if you need to hook up further events
        // you could also pass in further functions to setup each spawn

        var ps = spawn(cmds[i].shift(), cmds[i]);
        ps.on('exit', function() {
            done++; // keep track on how many commands have finished
            if (done === count) {
                callback();
            } 
        });
    }
}

multiSpawn([
    ['ls', '/usr/lib', '-l'],
    ['sleep', '1'], // this will sleep 1 seconds
    ['ls', '/usr/share', '-a']

], function() {
    console.log('all done');
});

这将运行所有3个命令,两个ls将立即完成,sleep将延迟1秒的所有内容,然后调用回调。

我想这对于Futures也是可能的,但在这种情况下,这很可能是过度杀伤。