3

I have an array of items on my $scope. For each of those items, I need to run three $http requests. These requests must run in a specific order, no matter whether there was a failure of not. I'm not sure how to do this elegantly, with the promise paradigm. I have a lot of duplicate code and it looks really confusing. I have to be doing this wrong. Currently, I have the following:

$scope.items = getItems();
$scope.currentIndex = 0;

$scope.executeItem = function() {
  $http.get($scope.items[$scope.currentIndex].urlA).then(
    function (resA) {
      $scope.items[$scope.currentIndex].urlAWorks = true;
      $http.get($scope.items[$scope.currentIndex].urlB).then(
        function (resB) {
          $scope.items[$scope.currentIndex].urlBWorks = true;

          $http.get($scope.items[$scope.currentIndex].urlC).then(
            function (resC) {
              $scope.items[$scope.currentIndex].urlCWorks = true;
              $scope.currentIndex = $scope.currentIndex + 1;
              $scope.executeItem();
            },

            function (errC) {
              $scope.items[$scope.currentIndex].urlCWorks = false;
              $scope.currentIndex = $scope.currentIndex + 1;
              $scope.executeItem();
            }
          )
        },
        function (errB) {
          $scope.items[$scope.currentIndex].urlBWorks = false;
        }
      );
    },

    function (errA) {
      $scope.items[$scope.currentIndex].urlAWorks = false;
      $http.get($scope.items[$scope.currentIndex].urlB).then(
        function (resB) {
          $scope.items[$scope.currentIndex].urlBWorks = true;

          $http.get($scope.items[$scope.currentIndex].urlC).then(
            function (resC) {
              $scope.items[$scope.currentIndex].urlCWorks = true;
              $scope.currentIndex = $scope.currentIndex + 1;
              $scope.executeItem();
            },

            function (errC) {
              $scope.items[$scope.currentIndex].urlCWorks = false;
              $scope.currentIndex = $scope.currentIndex + 1;
              $scope.executeItem();
            }
          )
        },
        function (errB) {
          $scope.items[$scope.currentIndex].urlBWorks = false;
        }
      );
    }
  );
};

Am I really chaining promises correctly? This looks WAY off.

Thank you

3
  • Do you need to request the data in order, or do you need to process it in order? Commented Oct 17, 2014 at 13:53
  • @Blazemonger request the data in order. Commented Oct 17, 2014 at 13:59
  • You might look into finding a way to get all the data in a single request, then. Commented Oct 17, 2014 at 14:09

2 Answers 2

3

You are underusing promises :) Since .then returns a promise, you could do:

$http.get(urlA)
  .then(function(dataA){
    DoStuffWithA(dataA);

    return $http.get(urlB);
  })
  .then(function(dataB){
    DoStuffWithB(dataB);

    return $http.get(urlC);
  })
  .then(function(dataC){
    DoStuffWithC(dataC);

    return true;
  })
Sign up to request clarification or add additional context in comments.

Comments

1

Just create references to those functions with a parameter binding. Instead of

      $http.get($scope.items[$scope.currentIndex].urlC).then(
        function (resC) {
          $scope.items[$scope.currentIndex].urlCWorks = true;
          $scope.currentIndex = $scope.currentIndex + 1;
          $scope.executeItem();
        },

        function (errC) {
          $scope.items[$scope.currentIndex].urlCWorks = false;
          $scope.currentIndex = $scope.currentIndex + 1;
          $scope.executeItem();
        }
      )

Do:

var next_thingy = function (worked) {
  return function () {
    $scope.items[$scope.currentIndex].urlCWorks = worked;
    $scope.currentIndex = $scope.currentIndex + 1;
    $scope.executeItem();
   }
}

$http.get($scope.items[$scope.currentIndex].urlC)
  .then(next_thingy(true),next_thingy(false));

Then chain them together:

var req1 = $http.get(...)
var thingies = {}

var thingies.next_thingy = function( worked) {
  return function() {
    var req = $http.get(...)
    ...
    req.then(thingies.next_thingy2(true),thingies.next_thingy2(false))
  }
}
req1.then(thingies.next_thingy(false),thingies.next_thingy(true))
var thingies.next_thingy2 = function(worked2) {
  return function() {
    var req2 = $http.get(...)
    ...
    req2.then(thingies.next_thingy3(true),thingies.next_thingy3(false); 
  }
}
var thingies.next_thingy3 = function(worked3) {
  return function() {
    ...
  }
}

You can fork them all off in parallel and then wait for them to finish with:

var third_reqs = []
$scope.items.forEach(function(item) {
   var third_req_defer = $q.defer()
   third_reqs.push(third_req_defer.promise)
   ...
    var thingies.next_thingy3 = function(worked3) {
      return function() {
       ...
       third_req_defer.resolve()
      }
   }
}) 
$q.all(third_reqs).then(
    function() { $log.log("Finished!")}, 
    function(){ $log.error("some third reqs failed.")})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.