view raw
Bigood Bigood - 6 months ago 39
Javascript Question

Return predicate from nested async function call

I need to filter an array, depending whether or not each element's sub-element, obtained by retrieving data from an external API, matches a criteria.

The code might be clearer than an explanation :

//Suppose there is an array filled
//_.filter(array, predicate)
var filtered_array = _.filter(array,function(element){
//Async operation
webservices.doStuff(element, function(sub_element){
//This return is meant for the filter, but returns on .doStuff callback
return sub_element.thing === "ok";
});
});


The problem here, is I don't know how to return the predicate's result here, as
webservices.doStuff
is asynchronous!

Any idea?

Answer

I would use Q or async to do this. Consider following example, you wrap each web service call in a promise and define another promise that will be resolved when all promises are resolved. Then you filter results ( ie array of all returns from all calls) according to your logic.

 var source = [{a : 1}, {a:2}...] // your 

 var all = Q.all(source.map((o) 
               => Q((success, error) 
                  => webService.do(o, success, error))))

 all.then(function(ret) {
     return filtered = _.filter(ret, function (data) {
              return data.thing === "ok"; 
     })
 }).then(function(filtered) {

    // do something with filtered

 })

Most likely your web service proxy already have binding with Q or another promise library. So your code is going to be simpler, something like:

var all = Q.all(source.map(webService.doStuff))

all.then(..)

Or at least you can refactor it to be that simple.

Overall due to non-blocking-accept-callback-and-go nature of node.js environment, it is essential to master one promise library or another, async and Q are two most popular to the best of my knowledge.

(Update: right now it seems to be bluebird, and it is fastest too.)

Having either of them allow you to come up with much easier design when dealing with async calls.