您的for 循环正在同时并行执行所有异步操作,因为exec() 是非阻塞的。他们将完成的顺序取决于他们的执行时间,并且不是确定的。如果你真的希望它们被排序,那么你必须执行一个,等待它调用它的完成回调,然后执行下一个。
您不能使用传统的for 循环“等待”异步操作以在 Javascript 中完成,以便按顺序执行它们。相反,您必须手动进行迭代,在前一个迭代的完成回调中启动下一个迭代。我通常的做法是使用一个计数器和一个名为 next() 的本地函数,如下所示:
手动异步迭代
var commands = ["npm install", "echo 'hello'"];
var exec = require('child_process').exec;
function runCommands(array, callback) {
var index = 0;
var results = [];
function next() {
if (index < array.length) {
exec(array[index++], function(err, stdout) {
if (err) return callback(err);
// do the next iteration
results.push(stdout);
next();
});
} else {
// all done here
callback(null, results);
}
}
// start the first iteration
next();
}
runCommands(commands, function(err, results) {
// error or results here
});
ES6 承诺
由于 Promises 在 ES6 中已经标准化并且现在内置到 node.js 中,我喜欢使用 Promises 进行异步操作:
var exec = require('child_process').exec;
function execPromise = function(cmd) {
return new Promise(function(resolve, reject) {
exec(cmd, function(err, stdout) {
if (err) return reject(err);
resolve(stdout);
});
});
}
var commands = ["npm install", "echo 'hello'"];
commands.reduce(function(p, cmd) {
return p.then(function(results) {
return execPromise(cmd).then(function(stdout) {
results.push(stdout);
return results;
});
});
}, Promise.resolve([])).then(function(results) {
// all done here, all results in the results array
}, function(err) {
// error here
});
蓝鸟承诺
使用 Bluebird Promise 库,这会更简单:
var Promise = require('bluebird');
var execP = Promise.promisify(require('child_process').exec);
var commands = ["npm install", "echo 'hello'"];
Promise.mapSeries(commands, execP).then(function(results) {
// all results here
}, function(err) {
// error here
});