Terry Chen
Terry Chen

Reputation: 133

Angular $q multiple promises

I am trying to do this:

  1. Run fun1
  2. Then after fun1 returns (promise resolves), run fun2 and fun3 in parallel (async)
  3. Then after fun2, 3 return (promises resolve), run some fun4 with different input all in parallel
  4. Then eventually run fun5 after all fun4 are resolved.

        $q.all({
            fun1: fun1()
        }).then(function(){
    
            return $q.all({
                fun2: fun2(),
                fun3: fun3(),
            });
    
        }).then(function(){
    
            var promises = [];
    
            for(var i = 0; i < 3; i += 1){
                promises.push(fun4(i));
            }
    
            return $q.all(promises);
    
        }).then(function(){
            fun5();
        });
    

fun 1~5 are all api calls similar to this pattern:

var funX = function(){
        return $http({
            method: 'GET',
            url: '/someURL'
        }).success(function(data, status, headers, config) {
            return;

        }).error(function(data, status, headers, config) {
            return new Error();
        });
    };

I want to make sure they are running in the order I describe above. Looks like fun4 did not wait for fun2 and fun3 to return, and fun5 did not wait for all fun4 to return too.

Upvotes: 2

Views: 679

Answers (2)

Ionut Costica
Ionut Costica

Reputation: 1392

As I said earlier, what's probably happening is that some of your Promises are failing. The best way to guard against the $http Promises failing would be to deal with the error in the .catch() (don't use .success() and .error() as they're deprecated) and return a truthy value.

Following is a test case trying to simulate your process failing (open up the console and see what gets logged):

angular.module('Test', [])
  .controller('Ctrl', function($q, Factory) {
    $q.all({
        fun1: Factory.succeedFunc('1')
      })
      .then(function() {
        return $q.all({
          fun2: Factory.failingFunc('2'),
          fun3: Factory.succeedFunc('3')
        });
      })
      .then(function() {
        var promises = [];
        for (var i = 0; i < 3; i++) {
          promises.push(Math.random() > 0.5 ? Factory.failingFunc('4: ' + i) : Factory.succeedFunc('4: ' + i));
        }
        return $q.all(promises);
      })
      .then(function() {
        Factory.succeedFunc('5');
      });
  })
  .factory('Factory', function($q, $timeout) {
    return {
      failingFunc: function(msg) {
        var deferred = $q.defer();
        console.log('executing', msg);
        $timeout(function() {
          console.log('failed', msg);
          deferred.reject();
        }, 500);
        return deferred.promise;
      },
      succeedFunc: function(msg) {
        var deferred = $q.defer();
        console.log('executing', msg);
        $timeout(function() {
          console.log('succeeded', msg);
          deferred.resolve();
        }, 1000);
        return deferred.promise;
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="Test" ng-controller="Ctrl">
</div>

And here is what happens when you deal with the rejection and return a value in the Promises' .catch() (though be careful not to throw in the .catch() as that will reject the newly created Promise too:

angular.module('Test', [])
  .controller('Ctrl', function($q, IgnoreErrors) {
    var Factory = IgnoreErrors;
    $q.all({
        fun1: Factory.succeedFunc('1')
      })
      .then(function() {
        return $q.all({
          fun2: Factory.failingFunc('2'),
          fun3: Factory.succeedFunc('3')
        });
      })
      .then(function() {
        var promises = [];
        for (var i = 0; i < 3; i++) {
          promises.push(Math.random() > 0.5 ? Factory.failingFunc('4: ' + i) : Factory.succeedFunc('4: ' + i));
        }
        return $q.all(promises);
      })
      .then(function() {
        Factory.succeedFunc('5');
      });
  })
  .factory('Factory', function($q, $timeout) {
    return {
      failingFunc: function(msg) {
        var deferred = $q.defer();
        console.log('executing', msg);
        $timeout(function() {
          console.log('failed', msg);
          deferred.reject();
        }, 500);
        return deferred.promise;
      },
      succeedFunc: function(msg) {
        var deferred = $q.defer();
        console.log('executing', msg);
        $timeout(function() {
          console.log('succeeded', msg);
          deferred.resolve();
        }, 1000);
        return deferred.promise;
      }
    };
  })
  .factory('IgnoreErrors', function(Factory) {
    return {
      failingFunc: function(msg) {
        return Factory.failingFunc(msg).catch(function() {
          return true;
        });
      },
      succeedFunc: function(msg) {
        return Factory.succeedFunc(msg).catch(function() {
          return true;
        });
      }
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="Test" ng-controller="Ctrl">
</div>

Upvotes: -1

Terry Chen
Terry Chen

Reputation: 133

So I was able to resolve this issue by using the new api and get rid of deprecated error and success.

Upvotes: 0

Related Questions