6

I have the following q.all calling to resolve two promises. I checked all the posts and tried all other ways of implementation q.all and its the same case

var xyzdeffered = $q.defer();
service1.getServiceDetail1($routeParams.id).then(function(promise) {
    xyzdeffered.resolve(promise);
});

var abcdeffered = $q.defer();
service2.getServiceDetail2($routeParams.id).then(function(promise) {
abcdeffered.resolve(promise);
});


$q.all([ xyzdeffered, abcdeffered ]).then(function(data) {

    $scope.variable = data;

});

I am expecting the variable in q.all should get populated only after the first two promises are resolved. But unfortunately the service call itself doesn't get returned with data and the control moves on to the q.all. I find this weird because as per documentation the q.all is called only when your promises are returned with 200 response and are resolved. I checked analysing the network calls and also put some alert to see the sequence of the code and find that the q.all alert is the first alert to be popped up and then the other promises are resolved. Its really making me mad as why a simple implementation of q.all doesnt work.. Any help will be appreciated.

Monish Das
  • 383
  • 2
  • 12
  • 28
  • 1
    Btw you felt into the most common anti-pattern: `service1.getServiceDetail1($routeParams.id)` is *already* a promise, why would you need to use `$q.defer` at all? Simply put these promises into your `$q.all` – floribon May 14 '15 at 22:36
  • Yes correct these are coded by somebody else.. i wanted to use the existing pattern..but you guys have already confirmed the implementation is wrong – Monish Das May 15 '15 at 14:52

3 Answers3

9

Why not directly call $q.all on first promise ?

$q.all([
    service1.getServiceDetail1($routeParams.id),
    service2.getServiceDetail2($routeParams.id)
]).then(function(data) {
    //Array of result [resultOfgetServiceDetails1, resultOfgetServiceDetails2]
    $scope.variable = data;
});
Kevin Davin
  • 511
  • 1
  • 4
  • 12
  • Thanks for confirmation Kevin.. i thought of using this before ..but as the code was written by someone else.. i just didnt want to change the implementation and use some work around... – Monish Das May 15 '15 at 14:35
8

You need to reference the promise on the $q.defer() return object:

$q.all([ xyzdeffered.promise, abcdeffered.promise ])
Ross Rogers
  • 23,523
  • 27
  • 108
  • 164
  • 1
    This is correct. Somewhat unrelated, I'd also highly recommend you place deferred calls into a service that returns a promise -- it gives you a cleaner and more reusable codebase. – AaronB May 14 '15 at 22:12
3

For example you have you run multiple sq-lite queries synchronously just pass the array of queries(you can pass anything) as args into the call of this method.

function methodThatChainsPromises(args,tx) {

    var deferred = $q.defer();

    var chain = args.map(function(arg) {

        var innerDeferred = $q.defer();

        tx.executeSql(arg,[], function(){    
            console.log("Success Query");
            innerDeferred.resolve(true);
        }, function(){
            console.log("Error Query");
            innerDeferred.reject();
        });

        return innerDeferred.promise;
    });

    $q.all(chain).then(
        function(results) {
            deferred.resolve(true)
            console.log("deffered resollve"+JSON.stringify(results));
        }, function(errors) {
              deferred.reject(errors);
              console.log("deffered rejected");
           });
           return deferred.promise;
        }
Kurt Van den Branden
  • 11,995
  • 10
  • 76
  • 85
Ahmad Ayyaz
  • 774
  • 8
  • 25