How can I delay execution of a function until two others have completed using $q?
angularjs, javascript
Solution
`$q.all` is what you're looking for. (Documentation)
`$q.all` takes multiple promises, either in an array or object, and returns a brand new promise that will be resolve when all the passed-in promises are resolved. If you passed in an array of promises, the new promise is resolved with an array of values which correspond to the promises:
$q.all([doTask1(), doTask2()]).then(function(results) {
// results[0] == result of doTask1
// results[1] == result of doTask2
doTask3();
});
If you passed in an object of key-promise pairs, it will be resolved with an object with keys that match the object you passed in, each value nicely corresponding to the value of that key's resolved promise:
$q.all({one: doTask1(), two: doTask2()}).then(function(results) {
// results.one == result of doTask1
// results.two == result of doTask1
doTask3();
});
Because of promise chaining (e.g., when you return a promise from a `then` function, it creates a new promise that resolves to the resolved value of the promise you returned), you can do some cool stuff:
var bothPromises = $q.all([doTask1(), doTask2()]);
var task3Promise = bothPromises.then(function(results) {
var result1 = results[0];
var result2 = results[1];
return doTask3(result1, result2);
});
task3Promise.then(function(resultOfDoTask3) { ... });
It is worth nothing that if any of the promises passed to `$q.all` is rejected, the promise that is returned will also be rejected. See the Angular `$q` documentation for more information.
This is (barely) tangential to the question, but I think it's a neat trick: if you happen to use CoffeeScript, you can use destructuring to get to the promises' resolved values.
For arrays:
$q.all([doTask1(), doTask2()]).then ([result1, result2]) ->
# ...
And for objects
$q.all(one: doTask1(), two: doTask2()).then ({one, two}) ->
# note that you have to use the same key names
# as in the object you passed to `$q.all`
Problem
I am using the AngularJS implementation of $q. Given the following functions: ``` doTask1: function ($scope) { var defer = $q.defer(); $http.get('/abc') .success(function (data) { defer.resolve(); }) .error(function () { defer.reject(); }); return defer.promise; }, doTask2: function ($scope) { var defer = $q.defer(); var x = 99; return defer.promise; }, ``` I know I can delay execution of another function like this: ``` os.doTask1() .then(function () { doTask3(); }); ``` I would like to start off doTask1 and doTask2 at the same time. Is there a way I can do this and still delay execution so that doTask3() will not execute until doTask1 and doTask2 have ended with success.