我正在尝试优雅地一个接一个地运行五个git命令,同时保持捕获错误和进度的能力:
开源说明:我研究过不同的node-git库,并决定自己实现它。
使用Q,我创建了一个延迟方法来运行子进程:
var exec = require('child_process').exec,
path = require('path'),
Q = require('q'),
gitPath = path.resolve(__dirname + "/../projects/langs");
function run(command) {
var deferred = Q.defer();
exec(command, {cwd: gitPath}, function puts(error, stdout, stderr) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.resolve(stdout);
}
});
return deferred.promise;
}
但是,我想避开Pyramid of doom:
function option1() {
// Pyramid of doom
run("git status").then(function (output) {
console.log(output);
run("git pull").then(function (output) {
console.log(output);
run("git add .").then(function (output) {
console.log(output);
// etc.
});
});
});
}
感觉不太优雅:
function options1a() {
// Pyramid of doom
run("git status").then(function (output) {
console.log(output);
run("git pull");
}).then(function (output) {
console.log(output);
run("git add .")
}).then(function (output) {
console.log(output);
});
}
我看到了第三种选择,但似乎无法让它发挥作用:
function promiseWaterfall(tasks) {
var resolvedPromise = Q(undefined);
var finalTaskPromise = tasks.reduce(function (prevTaskPromise, task) {
return prevTaskPromise.then(task);
}, resolvedPromise); // initial value
return finalTaskPromise;
}
promiseWaterfall([
run("git status"),
run("git pull"),
run("git add .")
]).then(function () {
console.log(arguments);
});
我正在玩第四个使用async库的选项:
async.waterfall([
function(callback){
callback(null, 'one', 'two');
},
function(arg1, arg2, callback){
callback(null, 'three');
},
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
但这似乎让我走向了一条不承诺的道路。
如何让它优雅地工作?任何最佳做法?
答案 0 :(得分:2)
我熟悉when.js promises,所以我将使用该承诺库回答您的问题。它提供了类似于基于回调的异步lib这类东西的辅助函数。查看他们的API documentation了解更多示例。
在下面的代码中,我使用when/sequence
模块来执行您要查找的内容。我还修改了你的代码组织,以保持模块化(例如,不在你的示例中将git cwd嵌入到run
函数中)。
这是一个完全有效的实施方案。确保将git cwd更改为您自己的git存储库,因为它当前指向我自己的存储库。
var exec = require('child_process').exec
, when = require('when')
, sequence = require('when/sequence');
// simple promise wrapper for exec
function exec_p(command, options) {
options = options || {};
var defer = when.defer();
exec(command, options, function(error, stdout, stderr) {
return error
? defer.reject(stderr + new Error(error.stack || error))
: defer.resolve(stdout);
});
return defer.promise;
}
// Some simple git wrapper
function Git(config) {
var self = this;
self.config = config;
return function(gitCommand) {
return exec_p('git ' + gitCommand, self.config);
};
}
// create a new instnace of git and specify our options
var git = new Git({ cwd: "/home/trev/git/tsenior" });
// we can now use sequence & our newly created git wrapper to easily
// can things in order one after another
sequence([
function() { return git('status'); },
function() { return git('status'); },
function() { return git('status'); },
function() { return git('status'); }
]).then(function(results) { // handle the results here
console.log(results);
}).otherwise(function(error) { // handle any errors here
console.error(error.stack || error);
process.exit(1);
});
每个步骤后提供的代码都不是console.log
(它只是在结尾处注销结果),但可以很容易地修改它来执行此操作。