How to handle multiple async tasks in angular.js?

angularjs, asynchronous, callback, javascript, mongodb

Solution

Promises and `$q.all` (ref) are your friends.

In more detail, you will have to make a promise for each call (if the call itself does not return one), push them in an array and call `$q.all(promises).then(allFinished)`. Naive case, where `$update()` does not return a promise:

function callUpdate(x, promises) {
    var d = $q.defer();
    x.$update({stateId: $scope.states[i].id}, function() {
        someFunction();
        d.resolve(); // it may be appropriate to call resolve() before someFunction() depending on your case
    });
    promises.push(d.promise);
}

...

var promises = [];
for (var i = 0; i < $scope.states.length; i++) {
    $scope.states[i].someProperty = someNewValue;
    callUpdate($scope.states[i], promises);
}

$q.all(promises).then(function() {
    // called when all promises have been resolved successully
});

The reason for the existence of `callUpdate()` is to encapsulate the deferred object handling and return the promise.

Problem

Working on a sandbox app to learn angular.js I have encountered the following pattern in several places in my code. I find myself having to query the mongoDB in a loop. As I understand it, each call happens in its own async task. How do I know when all the tasks are completed? For instance, I have an array of states. Often I need to set someProperty to someNewValue for each of the states. Once all the states have been updated I would like to call someFunction(). ``` for (var i = 0; i < $scope.states.length; i++) { $scope.states[i].someProperty = someNewValue; $scope.states[i].$update({stateId: $scope.states[i].id}, function() { someFunction(); }); } ``` For now, the only way I can think of doing this is to call someFunction() every time each update succeeds. I know there must be a smarter and better way of doing this. What would you be your approach?

Original source