bluebirdjs promises wrapped inside a for loop

前端 未结 2 1395
别那么骄傲
别那么骄傲 2021-01-25 04:25

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

2条回答
  •  清酒与你
    2021-01-25 04:53

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

提交回复
热议问题