web-dev-qa-db-fra.com

Comment abandonner correctement une chaîne de promesses node.js en utilisant Q?

J'utilise le module Q pour Node.js dans les tentatives pour éviter la "pyramide de Doom" dans les scénarios où j'ai plusieurs étapes. Par exemple:

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

Essentiellement, cela semble fonctionner; si une erreur est levée par l'une des étapes de la tâche, elle est transmise au rappel (bien que je serais le bienvenu aux améliorations, car je suis nouveau sur les promesses de node.js). Cependant, j'ai un problème lorsque j'ai besoin d'interrompre la chaîne de tâches tôt. Par exemple, si result1 est renvoyé avec succès, je pourrais vouloir appeler le rappel plus tôt et abandonner le reste, mais mes tentatives pour y parvenir échouent ...

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

Dans cet exemple, je vois les deux "abandonner!" et "faire l'étape 3 ..." imprimé.

Je suis sûr que je ne comprends pas bien certains principes de base ici, je vous serais reconnaissant de toute aide Merci!

35
Zane Claes

Toutes les erreurs qui sont lancées dans la chaîne de promesses entraîneront l'annulation précoce de la pile entière et le contrôle est donné au chemin de retour d'erreur. (dans ce cas, le gestionnaire fail ()) Lorsque vous détectez un certain état qui vous pousse à abandonner la chaîne de promesses, lancez simplement une erreur très spécifique, que vous piègez dans l'erreur-back et ignorez (si vous le faites) choisir)

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

Il s'agit d'un cas où vous devrez créer une branche, ce qui signifie soit imbriquer, soit créer un sous-programme.

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

Ou

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);
    })
}
37
Kris Kowal

Je crois que vous n'avez qu'à rejeter la promesse de sortir de la chaîne des promesses.

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

il semble également que .end () a été remplacé par .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();
}
2
George