Как использовать q.nfcall, если.then часть условна

Я использовал библиотеку Q на стороне сервера (nodejs), чтобы избежать пирамиды обратного вызова.

Пирамида обратного вызова, как показано ниже:

var isNext = <any boolean>;
db.model1.find({a: val}).exec().
then(function(err, res){
if( res && isNext){
  db.model2.find({b: val}).exec().then(function(err, res){ 
      callback();
  });
}else{
  callback();
}
});

Я использовал библиотеку q, чтобы избежать пирамиды обратного вызова следующим образом:

var isNext = <any boolean>;
q.nfcall(find1(id))
    .then( function( MODEL1 ){
        var deferred = q.defer();
        if( MODEL1 && isNext){
            deferred.promise = find2( id );
        }else{
            deferred.resolve(MODEL1);
        }
        return deferred.promise;
    })
    .fail(function(err){
        console.log('--> err : ' + JSON.stringify(err));
    })
    .done(function(){
        console.log('update done..');
       // main callback
    });

Функции find1 и find2 имеют вид:

function find1(id){
var deferred = q.defer();
db.model1.findOne({_id: id}).exec()
    .then(function(model){
        if( model ){
            // some operation
            deferred.resolve( model );
        }else{
            deferred.reject( 'error' );
        }
    },function(err){
        deferred.reject( err );
    }
);
return deferred.promise;
}

function find2(id){
var deferred = q.defer();
db.model2.findOne({_id: id}).exec()
    .then(function(model){
        if( model ){
            // some operation
            deferred.resolve( model );
        }else{
            deferred.reject( 'error' );
        }
    },function(err){
        deferred.reject( err );
    }
);
return deferred.promise;
}

Таким образом, проблема в том, что часть.then, когда используется библиотека Q, не выполняется. В этой проблеме вызов всегда идет в часть.fail выполнения. Я ожидаю, что выполнение должно идти внутри.then, когда выполняется вызов find1().

1 ответ

Решение

Ваш find1 функция уже возвращает обещание - вы не должны не использовать его с Q.nfcall,

Просто делать

var isNext = <any boolean>;
find1(id)
.then(function(MODEL1) {
    if (MODEL1 && isNext) {
        return find2(id);
    } else {
        return MODEL1; // you can just return plain values as well, btw
    }
})
.fail(function(err) {
    console.log('--> err : ' + JSON.stringify(err));
})
.done(function() {
    console.log('update done..');
    // main callback
});

Обратите внимание, что вам следует избегать отложенного антипаттерна. Те exec вызовы уже возвращают обещания, поэтому все, что вам может понадобиться, - это передать их Q обещания и отказ от ложных результатов.

function find1(id) {
    return q(db.model1.findOne({_id: id}).exec())
    .then(function(model) {
        if (model) {
            // some operation
            return model;
        } else {
            throw new Error('error');
        }
    });
}
function find2(id) {
    // analogous
}
Другие вопросы по тегам