bluebirdjs promises包含在for循环中

时间:2016-08-03 00:38:52

标签: node.js promise bluebird

我有一堆用于向我的服务提供数据的函数。我想循环遍历它们中的每一个并在其中一个返回所需结果时立即停止。如果第一个工作,那很好。如果它有例外或数据无效,我想转到下一个,依此类推。

我怎么能实现这个目标?我有以下代码:

SELECT`user_id`, SUM(total_deposit) AS total_deposit_amount, SUM(total_withdraw) AS total_withdraw_amount 
FROM (( SELECT user_deposit.user_id AS user_id, SUM(user_deposit.amount) AS total_deposit, null AS total_withdraw 
        FROM `user_deposit` 
        WHERE`date_time` BETWEEN '2016-07-01' AND '2016-07-31' 
        AND `user_deposit`.`status` = 1 
        GROUP BY `user_deposit`.`user_id`) 
        UNION ALL (SELECT user_withdraw.user_id AS user_id, null AS total_deposit, SUM(user_withdraw.amount) AS total_withdraw 
                   FROM `user_withdraw` 
                   WHERE `user_withdraw`.`created_at` BETWEEN '2016-07-01' AND '2016-07-31' 
                   AND `user_withdraw`.`status` = 1
                   GROUP BY `user_withdraw`.`user_id`)) t 
        GROUP BY `user_id`

如果第一个获得正确的数据,我该如何解决它?我已阅读handleData: function(address) { var self = this; return new Promise(function (resolve, reject) { for (var i = 0; i < self.listAllAvailableProviders.length; ++i) { var handler = self.listAllAvailableProviders[i]; new handler().getData(address) .then(function(value) { Logger.info(value); resolve(value); }) .catch(function(err){ Logger.error(err); }) } reject(""); }); } 文档无效。

修改 我在bluebirdjs之后添加了break语句,我得到了这个:

resolve

2 个答案:

答案 0 :(得分:2)

您正在for循环中并行运行所有请求,因此当您找到一个具有您喜欢的值时,其他请求已经启动,因此无法“不”运行它们。如果你想在找到其他人之后不再运行其他人,你就不需要并行启动它们了。因此,这将引导您进行序列化请求的设计模式。运行一个,如果不成功,运行下一个,依此类推。

据我所知,Bluebird中没有内置的方案可以满足您的要求。我能想到的最简单的事情是使用Bluebird中的一个数组处理函数,它将一个接一个地序列化请求,例如Promise.mapSeries(),然后在找到一个好的值时使用拒绝中止处理。

handleData: function(address) {
    return Promise.mapSeries(this.listAllAvailableProviders, function(handler) {
        return new handler().getData(address).then(function(value) {
            // the first success we get, we will throw with 
            // the returned value in order to stop the .mapSeries progression
            throw value;
        }, function(err) {
            // log the error, but don't let the rejection propagate so other handlers are called
            Logger.error(err);
        })
    }).then(function() {
        // nothing succeeded here, turn it into an overall rejection
        throw new Error("No getData() handlers succeeded");        
    }, function(val) {
        // reject here means we got a good value so turn it into a resolved value
        return val;
    })
}


// usage
obj.handleData().then(function(val) {
    // got value here
}).catch(function(err) {
    // no values here
});

奇怪的是,如果您只是自己迭代处理程序,它似乎代码更少,也许更简单一些:

handleData: function(address) {
    var index = 0;
    var handlers = this.listAllAvailableProviders;
    var handlerCnt = handlers.length;

    function next() {
        if (index < handlerCnt) {
            var handler = handlers[index++];
            return new handler().getData(address).catch(next);
        } else {
            return Promise.reject(new Error("No handler found for address"));
        }
    }
    return next();
}

答案 1 :(得分:0)

如果承诺不是硬约束caolan/async#eachSeries或类似可能有帮助。有点像...

// var Promise = require(?)
// var async = require("async")
handleData: asyncProviderFinder

...

function asyncProviderFinder(address){
  var self = this;
  return new Promise(function(resolve, reject){
    async.eachSeries(
      self.listAllAvailableProviders, 
      function iterate(provider, next){
        var handler = provider;
        new handler().getData(address)
        .then( function(value){
          Logger.info(value);
          next("abort"); // callback any error to abort future iterations
          return resolve(value);
        })
        .catch( function (err){
          Logger.error(err);
          next();
        });
      },
      function callback(err, firstProvider){
        if ((firstProvider === undefined) && !err ){ reject(""); }
      }
    );
  });
}