bluebirdjs promises wrapped inside a for loop

匿名 (未验证) 提交于 2019-12-03 02:33:02

问题:

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

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.

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) 

回答1:

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.

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


回答2:

if promises are not a hard constraint caolan/async#eachSeries or similar might help. Something like...

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!