bluebirdjs承诺包装在for循环中 [英] bluebirdjs promises wrapped inside a for loop

查看:50
本文介绍了bluebirdjs承诺包装在for循环中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堆函数用于向我的服务提供数据.我想遍历它们中的每一个,并在其中一个返回所需结果后立即停止.如果第一个可行,那就可以了.如果有异常或数据无效,我想移到下一个,依此类推.

I have a bunch of functions used to provide data to my service. I want to loop through each of them and stop as soon as one of them returns the desired result. If the first one works, thats fine. If it has an exception or data is not valid, I would like to move to the next one and so on.

我该如何实现?我有以下代码:

How may I achieve this? I have the below code:

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 文档.

how can I fix it to stop as soon as the first one gets the right data? I have read through the bluebirdjs documentation to no avail.

编辑我在 resolve 之后放置了 break 语句,我明白了:

EDIT I put a break statement after resolve and I got this:

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 循环中并行运行所有请求,因此当您找到一个具有所需值的对象时,其他对象已经开始,所以没有办法不"运行它们.如果不想在找到其他计算机后立即运行它们,则无需并行启动它们.因此,这将导致您进入序列化请求的设计模式.运行一个,如果没有成功,请运行下一个,依此类推.

You are running all your requests in parallel in the for loop so when you find one that has a value you like, the others have already been started so there's no way to "not" run them. If you want to not run the others once you've found one, you need to not start them in parallel. So, that would lead you to a design pattern where you serialize the requests. Run one, if it doesn't succeed, run the next and so on.

据我所知,Bluebird中没有内置的方案可以执行您的要求.我能想到的最简单的事情是使用Bluebird中的一个数组处理功能,该功能将一个接一个地序列化请求,例如 Promise.mapSeries(),然后使用拒绝来中止处理当您发现有价值的东西时.

As best I can tell, there isn't a built-in scheme in Bluebird for doing what you're asking. The simplest thing I can think of is to use one of the array processing functions in Bluebird that will serialize the requests one after the other such as Promise.mapSeries() and then use a rejection to abort the processing when you found a good value.

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


奇怪的是,如果您自己迭代处理程序,它似乎更少的代码,并且可能会更简单:


Curiously enough, it seems to be less code and perhaps a bit simpler if you just iterate the handlers yourself:

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

这篇关于bluebirdjs承诺包装在for循环中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆