Sequelize等到循环完成回调

时间:2015-02-13 16:00:20

标签: javascript node.js promise sequelize.js

来自php背景,我试图了解这个回调的东西。

基本上我想获得一些行,然后我想循环遍历这些行并检查它们与另一个模型(不同的数据库)。我希望电话回来等待它们全部通过并检查。

在sequelize循环遍历所有结果之前调用回调。

基本上我希望这个功能是'阻塞'。我需要改变什么?

toexport.getlasttransactions = function(lower,upper,callback){
    var deferred = Q.defer();
    var transactionsToUpdate = [];
    ///////////////////////////
    // set import conditions //
    ///////////////////////////
    var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
    var upperbound = (upper) ? upper.format() : moment.utc().format();

    ///////////////////////////////
    // get IDs From Failed syncs //
    ///////////////////////////////
    FailedSync.find({ limit: 100 })
    .then(function(res){
        var FailedIDs = [];
        _.each(res, function(value,index){
            FailedIDs.push(value.transaction_id);
        });

        // build condition
        var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
        if(FailedIDs.length > 0){
            queryCondition = {
                where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
                Sequelize.or(
                  { id: FailedIDs }
                ))
            }
        }
        //////////////////////////////
        // get Phoenix Transactions //
        //////////////////////////////
        PhoenixTransaction
        .findAll(queryCondition)
        .then(function(poenixTrx){

            _.each(poenixTrx, function(value, index){

                Transaction.findOne({ where: { id: value.id }})
                .then(function(result){

                    if(!result || result.length === 0){
                        transactionsToUpdate.push(value);
                        console.log('!result || result.length === 0')
                    }
                    else if(result && result.length === 1){
                        if(result.hash != value.hash){
                            transactionsToUpdate.push(value);
                            console.log('result.hash != poenixTrx[i].hash')
                        }
                    }




                })
                .catch(function(err) {
                  console.log(err)
                })


            })
            deferred.resolve(transactionsToUpdate);


        })
        .catch(function(err){
          throw new Error("Something went wrong getting PhoenixTransaction") 
        })

    })

    deferred.promise.nodeify(callback);
    return deferred.promise;    

}

4 个答案:

答案 0 :(得分:3)

您的代码中有许多新承诺用户拥有的模式:

  • 当您不需要时,您会使用延期。
  • 您未使用承诺汇总方法
  • 你不是在适当的地方等待事情而是筑巢。

承诺代表值随着时间的推移。您可以在以后通过then使用promises并访问其结果,而不仅仅是立即 - Sequelize的承诺基于bluebird并提供丰富的API,为您进行聚合。 这是清理代码的注释版本 - 注意它不是嵌套:

toexport.getlasttransactions = function(lower,upper){ // no need for callback
    var lowerbound = (lower || moment.utc().subtract(10, 'minutes')).format();
    var upperbound = (upper || moment.utc()).format();
    // use `map` over a `each` with a push.
    var failedIds = FailedSync.find({ limit: 100 }).map(function(value){ 
        return value.transaction_id;
    });
    // build condition.
    var queryCondition = {
        where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 
    };
    var query = failedIds.then(function(ids){ // use promise as proxy
        if(ids.length === 0) return queryCondition;
        return { // You can return a value or a promise from `then`
            where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
                   Sequelize.or({ id: ids});
        };
    });
    var pheonixTransactions = query.then(function(condition){
        return PhoenixTransaction.findAll(queryCondition); // filter based on result
    });
    return pheonixTransactions.map(function(value){ // again, map over each
        return Transaction.findOne({ where: { id: value.id }}); // get the relevant one
    }).filter(function(result){ // filter over if chain and push
        return (!result || result.length === 0) || 
               ((result && result.length === 1) && result.hash != value.hash);
    });
};

答案 1 :(得分:0)

理想情况下,您希望使用一系列承诺来使用Bluebird&reduce减少的内容,但我会提供async.series实现,因为它更容易理解。

安装异步

npm install async

在文件中要求

var async = require('async')

然后实现它:

        //////////////////////////////
        // get Phoenix Transactions //
        //////////////////////////////
        PhoenixTransaction
        .findAll(queryCondition)
        .then(function(poenixTrx){

            var queryArray = poenixTrx.map(function(value){
                return function(callback){
                    Transaction.findOne({ where: { id: value.id }})
                    .then(function(result){

                        if(!result || result.length === 0){
                            transactionsToUpdate.push(value);
                            console.log('!result || result.length === 0')
                        }
                        else if(result && result.length === 1){
                            if(result.hash != value.hash){
                                transactionsToUpdate.push(value);
                                console.log('result.hash != poenixTrx[i].hash')
                            }
                        }

                        // trigger callback with any result you want
                        callback(null, result)
                    })
                    .catch(function(err) {
                      console.log(err)
                      // trigger  error callback
                      callback(err)
                    })
                }

            })

            // async.series will loop through he queryArray, and execute each function one by one until they are all completed or an error is thrown.
            // for additional information see https://github.com/caolan/async#seriestasks-callback
            async.series(queryArray, function(err, callback){
                // after all your queries are done, execution will be here
                // resolve the promise with the transactionToUpdate array
                deferred.resolve(transactionsToUpdate);
            })


        })
        .catch(function(err){
          throw new Error("Something went wrong getting PhoenixTransaction") 
        })

答案 2 :(得分:0)

说实话,整件事情有点混乱。特别是承诺/回调混乱可能会在某些时候引起你的问题。无论如何,你在transactionsToUpdate上使用deferred.resolve,它只是一个数组,所以它立即调用回调。

如果您保留该脚本,而不是使用_.each async(https://github.com/caolan/async)来运行您在paralell中的事务并将其用作回调。

看起来像这样:

toexport.getlasttransactions = function(lower,upper,callback){
    var transactionsToUpdate = [];
    ///////////////////////////
    // set import conditions //
    ///////////////////////////
    var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
    var upperbound = (upper) ? upper.format() : moment.utc().format();

    ///////////////////////////////
    // get IDs From Failed syncs //
    ///////////////////////////////
    FailedSync.find({ limit: 100 })
    .then(function(res){
        var FailedIDs = [];
        _.each(res, function(value,index){
            FailedIDs.push(value.transaction_id);
        });

        // build condition
        var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
        if(FailedIDs.length > 0){
            queryCondition = {
                where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
                Sequelize.or(
                  { id: FailedIDs }
                ))
            }
        }
        //////////////////////////////
        // get Phoenix Transactions //
        //////////////////////////////
        PhoenixTransaction
        .findAll(queryCondition)
        .then(function(poenixTrx){

            async.each(poenixTrx, function(value, next){

                Transaction.findOne({ where: { id: value.id }})
                .then(function(result){

                    if(!result || result.length === 0){
                        transactionsToUpdate.push(value);
                        console.log('!result || result.length === 0')
                    }
                    else if(result && result.length === 1){
                        if(result.hash != value.hash){
                            transactionsToUpdate.push(value);
                            console.log('result.hash != poenixTrx[i].hash')
                        }
                    }

                    next();
                })
                .catch(function(err) {
                  console.log(err)
                })


            }, function(err) {
              //Return the array transactionsToUpdate in your callback for further use
              return callback(err, transactionsToUpdate);
            });
        })
        .catch(function(err){
          throw new Error("Something went wrong getting PhoenixTransaction") 
        })

    })

}

这将是回调的方式。 但是你需要根据自己想要使用的内容进行思考:回调或承诺。不要同时使用它们(如:如果你的方法需要回调,它不应该返回一个promise,或者如果它返回一个promise它不应该期望一个回调)。

如果你使用回调你不想抛出错误,你只需要调用回调并在回调中给出错误 - 使用你的方法的任何人都可以检查回调中的错误并处理它。

希望你有点意义,我知道整个回调和承诺事情有点奇怪,如果你来自像php这样的东西,它需要一些习惯:)

答案 3 :(得分:0)

感谢您解释这些差异。我认为使用promises是前进的方向,因为它使代码看起来更好并且避免了这个"回调地狱"。

例如:

PhoenixSyncTransactions.getlasttransactions(lastTimeSynced,null)
.then(function(res){

    return PersistTransaction.prepareTransactions(res).then(function(preparedTrx){
      return preparedTrx;
    })
}).then(function(preparedTrx){
    return PersistTransaction.persistToDB(preparedTrx).then(function(Processes){
      return Processes;
    })
})
.then(function(Processes){
    return PersistTransaction.checkIfMultiProcess(Processes).then(function(result){
      return result;
    })

})
.then(function(result){
  console.log('All jobs done');
})

整个代码更容易阅读。