我在Node.js中使用the Q module试图在我有很多步骤的场景中避免“厄运金字塔”。例如:
function doTask(task, callback)
{
Q.ncall(task.step1, task)
.then(function(result1){
return Q.ncall(task.step2, task);
})
.then(function(result2){
return Q.ncall(task.step3, task);
})
.fail(callback).end();
}
基本上这似乎有效;如果任何任务步骤引发错误,它将被传递给回调(尽管我欢迎改进,因为我是node.js promises的新手)。但是,当我需要尽早中止任务链时,我遇到了问题。例如,如果result1成功返回,我可能希望尽早调用回调并中止其余的回调,但我尝试这样做是失败的......
function doTask(task, callback)
{
Q.ncall(task.step1, task)
.then(function(result1){
if(result1)
{// the rest of the task chain is unnecessary
console.log('aborting!');
callback(null, result1);
return null;
}
return Q.ncall(task.step2, task);
})
.then(function(result2){
console.log('doing step 3...');
return Q.ncall(task.step3, task);
})
.fail(callback).end();
}
在这个例子中,我看到两个“中止!”和“做第3步......”印刷。
我确信我只是在这里误解了一些基本原则,所以我将不胜感激。谢谢!
答案 0 :(得分:35)
这是您需要分支的情况,这意味着嵌套或创建子例程。
function doTask(task, callback) {
return Q.ncall(task.step1, task)
.then(function(result1) {
if (result1) return result1;
return Q.ncall(task.step2, task)
.then(function(result2) {
return Q.ncall(task.step3, task);
})
})
.nodeify(callback)
}
或者
function doTask(task, callback) {
return Q.ncall(task.step1, task)
.then(function(result1) {
if (result1) {
return result1;
} else {
return continueTasks(task);
}
})
.nodeify(callback)
}
function continueTasks(task) {
return Q.ncall(task.step2, task)
.then(function(result2) {
return Q.ncall(task.step3, task);
})
}
答案 1 :(得分:17)
在promise链中抛出的任何错误都会导致整个堆栈提前中止,并且会对错误返回路径进行控制。 (在这种情况下,fail()处理程序)当您检测到某个导致您想要中止promise链的状态时,只需抛出一个非常特定的错误,您将在错误返回中陷入并忽略(如果您这样做)选择)
function doTask(task, callback)
{
Q.ncall(task.step1, task)
.then(function(result1){
if(result1 == 'some failure state I want to cause abortion')
{// the rest of the task chain is unnecessary
console.log('aborting!');
throw new Error('abort promise chain');
return null;
}
return Q.ncall(task.step2, task);
})
.then(function(result2){
console.log('doing step 3...');
return Q.ncall(task.step3, task);
})
.fail(function(err) {
if (err.message === 'abort promise chain') {
// just swallow error because chain was intentionally aborted
}
else {
// else let the error bubble up because it's coming from somewhere else
throw err;
}
})
.end();
}
答案 2 :(得分:2)
我相信你只需要拒绝摆脱承诺链的承诺。
https://github.com/kriskowal/q/wiki/API-Reference#qrejectreason
似乎.end()已更改为.done()
function doTask(task, callback)
{
Q.ncall(task.step1, task)
.then(function(result1){
if(result1)
{// the rest of the task chain is unnecessary
console.log('aborting!');
// by calling Q.reject, your second .then is skipped,
// only the .fail is executed.
// result1 will be passed to your callback in the .fail call
return Q.reject(result1);
}
return Q.ncall(task.step2, task);
})
.then(function(result2){
console.log('doing step 3...');
return Q.ncall(task.step3, task);
})
.fail(callback).done();
}