Как правильно прервать узел.цепь обещания js используя Q?

Я использую модуль Q для узла.js в попытках избежать "пирамиды гибели" в сценариях, где у меня много шагов. Например:

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();
}

по существу это, кажется, работает; если ошибка вызвана любым из шагов задачи, она передается обратному вызову (хотя я был бы рад улучшениям, поскольку я новичок в узле.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..." напечатанный.

Я уверен, что я просто неправильно понимаю некоторые основные принципы здесь, поэтому был бы признателен за любую помощь. Спасибо!

3 ответов


любые ошибки, которые выбрасываются в цепочке обещаний, приведут к тому, что весь стек будет прерван рано, и управление будет дано пути возврата ошибок. (в этом случае обработчик 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();
}

это случай, когда вам нужно будет ветвиться, что означает либо вложенность, либо создание подпрограммы.

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);
    })
}

Я считаю, что вам нужно только отклонить обещание вырваться из цепи обещаний.

https://github.com/kriskowal/q/wiki/API-Reference#qrejectreason

тоже похоже .end() был изменен на .сделано()

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();
}