Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle multiple async tasks in angular.js?

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?

like image 265
Francesco Gallarotti Avatar asked Dec 03 '13 09:12

Francesco Gallarotti


People also ask

Is angular sync or async?

A common misconception in Angular development is regarding whether observables are synchronous or asynchronous. A lot of (even experienced Angular developers) think that observables are async, but the truth is that they can be… Both synchronous and asynchronous.

How do I handle multiple async await?

In order to run multiple async/await calls in parallel, all we need to do is add the calls to an array, and then pass that array as an argument to Promise. all() . Promise. all() will wait for all the provided async calls to be resolved before it carries on(see Conclusion for caveat).

Do async functions run in parallel?

Asynchronous operations in parallelThe method async. parallel() is used to run multiple asynchronous operations in parallel. The first argument to async. parallel() is a collection of the asynchronous functions to run (an array, object or other iterable).


1 Answers

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.

like image 104
Nikos Paraskevopoulos Avatar answered Oct 05 '22 08:10

Nikos Paraskevopoulos