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?
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.
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).
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With