Resolving Multiple Asynchronous Functions Just Once with Deferred Objects / Promises

I recently came across a piece of legacy code that had to pull data from multiple sources via AJAX requests, then combine it all. A simplified version looks like this:

var retrieveOne = function(source, cb) {
    $http.get(source).success(function(data){
        cb(data);
    });
};

var retrieveMany = function(sources, cb) {
    var dataArray = [];
    var _combine = function(data){
        if(data)
            dataArray.push(data);
        if(dataArray.length !== sources.length)
            return;
        //Continue combine...
        cb(dataArray);
    };
    for(var i = 0; i < sources.length; i++){
        retrieveOne(sources[i], _combine);
    }
};

retrieveMany([url1, url2, ...], processData);

It works, but it’s not great. We’re calling the private function _combine multiple times, when we really should be calling it once. The biggest drawback to this that comes to mind is that we wouldn’t be able to return anything from a deeper function call, at least not in a clean manner. Plus, there’s just better ways of doing it. It’s when() in jQuery, all() in Q and Angular. Let’s take a look at how you might handle multiple AJAX requests in Angular.

var retrieveOne = function(source) {
    return $http.get(source); 
};

var retrieveMany = function(sources, cb) {
    var promises = [];
    for(var i = 0; i < sources.length; i++){
        promises.push(retrieveOne(sources[i]));
    }
    $q.all(promises).then(function(values){
        cb(values);
    });
};

retrieveMany([url1, url2, ...], processData);

As you can see, we give $q.all an array of promises. When all the promises are ready to be resolved, then we can pass the promises’ values to a callback function, which we will only call once. Values are passed back to us from all() as an array of values in the order of the array of promises. Should you pass a hash of promises to all(), then the values will be in the same key as the hash. This way, we only have to resolve the promises once. Plus, we now have a single path to pass back any value that needs to be returned!

 
8
Kudos
 
8
Kudos

Now read this

Javascript Floating Point (im)Precision and Solution

In an exercise to re-implement Javascript’s parseFloat(), I came across a common gotcha. Go ahead, try it yourself: var pointThree = 0.1 + 0.2; console.log(pointThree === 0.3); No, your console isn’t broken. 0.1 + 0.2 ==... Continue →