36

我正在使用Node.js的 Q 模块,试图在我有很多步骤的情况下避免“厄运金字塔”。例如:

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 承诺的新手)。但是,当我需要提前中止任务链时,我遇到了问题。例如,如果 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 步...”。

我敢肯定,我只是在这里误解了一些基本原则,因此不胜感激。谢谢!

4

3 回答 3

39

这是您需要分支的情况,这确实意味着嵌套或创建子例程。

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);
    })
}
于 2013-01-28T03:32:13.293 回答
20

在 Promise 链中抛出的任何错误都将导致整个堆栈提前中止,并将控制权交给错误返回路径。(在这种情况下,fail() 处理程序)当您检测到导致您想要中止承诺链的某个状态时,只需抛出一个非常具体的错误,您将其捕获在错误返回中并忽略(如果您这样选择)

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();
}
于 2013-09-03T23:16:06.163 回答
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();
}
于 2016-04-11T18:08:17.260 回答