2 $http get function

2019-08-13 09:40发布

问题:

Given 2 JSON url, how do I make sure the code has finished retrieving the data from a.json, then only start retrieving the data from b.json, then only run init function?

var aUrl = "a.json";
var bUrl = "b.json"; 

My attempt:

var app = angular.module('calendarApp', []);
app.controller('ctrl', function($scope, $http) { 
  $http.get(aUrl).success(function(data) {   }); 
  $http.get(bUrl).success(function(data) {  
   init()}
);
var init = function(){}

回答1:

I faced the same issue in my initial days.
There are many ways of doing it exactly as suggested here.
You need to know below two things before exploring:

1. JavaScript is synchronous

Synchronous Example[Flow in sequence]:
       console.log('1')
       console.log('2')
       console.log('3')

It logs 1 2 3.

Example of making service calls

   1. $http.get(aUrl).success(function(data) {  console.log('1.any time response returns')  });  
   2. $http.get(bUrl).success(function(data) { console.log('2.mummy returns')};

So as single-threaded javascript will first make a call to your below code with $http.get(aUrl) which hits the url and processes to fetch the data from the background.

  1. $http.get(aUrl).success(function(data) { console.log('1.any time response returns') });

But the key thing to notice here is $http.get(aUrl) requested above doesn't wait until the data is returned in success/error. It moves to the next request $http.get(bUrl) and we just can't predict which response comes earlier.

  1. $http.get(bUrl).success(function(data) { console.log('2.mummy returns') }

Output might be either

1.any time response returns

2.mummy returns

                     or

2.mummy returns

1.any time response returns

So, to overcome this situation we follow asynchronous operations in various ways.

2. Asynchronous Calls

$http.get(aUrl)
    .then(function(response){
      console.log('inside the first then response');
      console.log(response.data);

      //executing the second request after we get the first request
     //and returns the **outputResponse** which is captured in the next **then** block
      return $http.get(bUrl);
    })
    .then(function(**outputResponse** ){
      console.log('outputResponse generated from to the second bUrl');
      //you can call init() here 
    });

Above code suffices your requirement.

Click for more info using $q in future

Click here to know why to use then instead of success.



回答2:

Might not be the best or cleanest method but quickly making your code do what you want it to do I got:

var app = angular.module('calendarApp', []);
app.controller('ctrl', function($scope, $http) { 
  $http.get(aUrl).success(function(data) {   
      $http.get(bUrl).success(function(data) {  
         init()
      }
  }); 
);
var init = function(){}


回答3:

You could create a service layer in which define the two methods. Then inject the service into your controller:

//Controller
YourService.getUrl(urlA).then(function(response) {

            if(response != null && response.success == true){
                // do something
            }
            YourService.getUrl(urlB).then(function(response) {

                if(response != null && response.success == true){
                    // do something
                    init()
                }
            }, 
            function errorCallback(response) {

                console.log("Error YourService: getUrlB ---> ");
            }); 
        }, 
        function errorCallback(response) {
            console.log("Error YourService: getUrlA ---> ");
        });

// Example of method in your service    
this.getUrl = function(urlA) {
    try{
        var deferred = $q.defer();

        $http({
            method: 'GET',
            url: getUrlA,
            params: {},
            responseType: "json",
            cache: false
        })
        .success(function(data, status, headers, config) {

            deferred.resolve(data);
        })
        .error(function(data, status, headers, config) {

            deferred.reject(data);
        });

        return deferred.promise;
    }catch(e){
        /* */
        console.log("Service: getUrl ---> " + e);
    }
}


回答4:

$http.get returns a promise, so you can do:

return $http.get(aUrl)
    .then(function(result) {
        return $http.get(bUrl);
    })
    .then(function(result) {
        return init();
    },
    function (error) {
        // do something with the error
    });


回答5:

I suggest to use AngularJS promises. Mainly it has the benefit of loading the data asynchronly at the same time without having to wait until the first request is finished. see: https://docs.angularjs.org/api/ng/service/$q

var promises = [];

var loadingJson = function(url){
  var defer = $q.defer();

  $http.get(url).then(function(results){
    defer.resolve(results);
  }, function(err){
    defer.reject(err);
  });

  return defer.promise;
};

promise.push(loadingJson('example.com/1.json'));
promise.push(loadingJson('example.com/2.json'));

$q.all(promises).then(function(resultList){
  // Your hanadling here, resultList contains the results of both API calls.
}, function(errList){
  // Your error handling here.
});