Recursive $http.get in for loop

2019-02-18 11:25发布

问题:

I use Angular 1.5. I have a function that queries Categories, then for each category, it queries Products. I want to show a message after all the products are retrieved, how many were retrieved. It outputs 0. What is the solution?

function getProducts() {
  vm.categories = [];
  var prodcount = 0;

  $http.get("localhost/menu/1/categories")
    .then(function(response) {
      var categories = response.data;
      angular.forEach(categories, function(cat) {
        $http.get("localhost/category/" + cat.id + "/products")
          .then(function(response) {
            cat.products = response.data;
            vm.categories.push(cat);
            prodcount += cat.products.length;
          });
      });
      $mdToast.show($mdToast.simple().textContent("retrieved " + vm.categories.length + " categories and, " + prodcount + " products!."));
    });
}

回答1:

You should take a look at how asynchronous requests and promises works. To make your code run you could do this: var promises = []; // Creates an array to store the promises

angular.forEach(categories, function(cat) {

    // Capture the promise
    var requestPromise = $http.get(...)
    .then(function(response) {
        ...
    });
    promises.push(requestPromise);  // Add it to the array
  });

  // This promise will be resolved when all promises in the array have been resolved as well.
  $q.all(promises).then(function(){
     $mdToast.show(...);
  })

});

But this approach is not quite good. You should try to minimize the amount of requests, doing only one preferably.

http://www.martin-brennan.com/using-q-all-to-resolve-multiple-promises/ http://andyshora.com/promises-angularjs-explained-as-cartoon.html



回答2:

you can map your array of categories into an array of promises and then use $q.all to wait for them all to finish

function getProducts() {
    vm.categories = [];
    var prodcount = 0;

    $http.get("localhost/menu/1/categories")
            .then(function (response) {
                var categories = response.data;
                $q.all(categories.map(function (cat) {
                    return $http.get("localhost/category/" + cat.id + "/products")
                            .then(function (response) {
                                cat.products = response.data;
                                vm.categories.push(cat);
                                prodcount += cat.products.length;
                            });
                })).then(function () {
                    $mdToast.show($mdToast.simple().textContent("retrieved " + vm.categories.length + " categories and, " + prodcount + " products!."));
                });
            });
}