【问题标题】:bluebirdjs promises wrapped inside a for loopbluebirdjs 承诺包装在 for 循环中
【发布时间】:2016-12-08 12:36:47
【问题描述】:

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

我怎样才能做到这一点?我有以下代码:

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 文档,但无济于事。

编辑 我在resolve 之后放了一个break 声明,我得到了这个:

SyntaxError: Illegal break statement
at Object.exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:513:28)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)

【问题讨论】:

  • 您在for 循环中并行运行所有请求。当您找到您喜欢的结果时,所有其他请求都已启动。您可以一次序列化您的请求,然后仅在没有找到您喜欢的答案时才继续处理下一个请求。这就是你想要的吗?
  • 能否进一步解释一下序列化?我想要第一个成功的,所以如果一个不起作用,那么尝试下一个。这是使用sailsjs
  • 解释什么?我不知道你不明白我评论的哪一部分。你想序列化你的请求(一次运行一个)吗?
  • 是的,可以。但我处于一个一切都在承诺的情况下......

标签: node.js promise bluebird


【解决方案1】:

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

【讨论】:

  • 你的第二个答案是对的!也很有意义。
  • @KVISH - 我也喜欢第二个,但我想我解决了第一个的问题。
【解决方案2】:

如果承诺不是硬约束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(""); }
      }
    );
  });
}

【讨论】:

  • 不熟悉那个库。但是当我安装库和var async = require("async");时,您的代码甚至都没有运行?
  • 我收到错误:return new Promise(function resolve, reject) { ^ SyntaxError: Unexpected token , at Object.exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:513:28)
猜你喜欢
  • 2023-03-17
  • 2020-05-14
  • 2015-12-18
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 2017-12-10
相关资源
最近更新 更多