synchronous and asynchronous calling in angularJS with promise and defer

43,669

Solution 1

To make sure the second calls are executed after the first one is finished, put the second call within then of the first call. To make multiple 'second' calls depending on the number of results of the first call, use $q.all.

asyncService.loadDataFromUrls('api/first/')
.then(function(firstData) {
    //assuming firstData is an array of 'x' items, do a call for each of these items:
    console.log('results of first call holds ' + firstData.length + ' items');
    var promises = [];
    for(var i = 0; i<firstData.length; i++){
        var id = firstData[i].id;//you can use this to pass to the second call
        promises.push(asyncService.loadDataFromUrls('api/second'));
    }
    return $q.all(promises);
})
.then(function(results) {
  //'results' is an array of results, the nth item holds the result of the 'nth' call to loadDataFromUrls
  for(var i = 0; i<results.length; i++){
    console.log('result nr. ' + i + ' :' + results[i])
  }
});

By using return $q.all(promises), you're avoiding the promise pyramid of doom, and keep a flat structure.

Your service code doesn't need to loop anymore. As a sidenote, you can shorten the code of the service and avoid using the 'explicit promise construction antipattern' (see here) like this:

app.service('asyncService', function($http, $q) 
{
    return {
        loadDataFromUrls: function(url) 
        {
            return $http.get(WSURL + url, {
                headers: {
                  "Authorization": 'Bearer <my-token>'
                }
            }).then(function(response){ return response.data; });
        }
    };
});

Solution 2

Your asyncService seems completely unnecessary and unuseful.

It sounds like you just need to learn how to chain promises and use $q.all correctly:

function queryApi(subUrl) {
    return $http.get(WSURL + subUrl, {
        headers: {
            "Authorization":'Bearer <my-token>'
        }
    }).then(function (result) { return result.data; });
}

queryApi('api/first/')
    .then(function (data) { 
        return $q.all(data.map(function (entry) {
            return queryApi('api/second/' + entry.id);
        }));
    })
    .then(function (results) {
         console.log(results);
    });

Solution 3

put second request inside first request promise:

 var mycompaigndata = [];

asyncService.loadDataFromUrls($http.get(WSURL + 'api/first/', 
{
   headers: 
   {
    "Authorization":'Bearer <my-token>'
   }
 }))
.then(function(data)
{
    asyncService.loadDataFromUrls($http.get(WSURL + 'api/second', 
         {
           headers:
         {
         "Authorization":'Bearer <my-token>'
          }
        }))
        .then(function(data)
        {   
         console.log(data);
    });
});

Solution 4

I think the best answer is to use loop since you need to iterate the response to get the id.

asyncService.loadDataFromUrls(WSURL + 'api/first/')
    .then(function(data) {
         //iterate to get the id
           //call service again
            asyncService.loadDataFromUrls(WSURL + 'api/first/')
                .then(function(data) {
                     //code here
                });
     });

Service

app.service('asyncService', function($http, $q) {
    return {
         loadDataFromUrls: function(url) {
              return $http.get(url, {
                  "Authorization":'Bearer <my-token>'  
              });
         }
    };
});
Share:
43,669
Paresh Gami
Author by

Paresh Gami

Zero! Code! Form! http://zerocodeform.com Generate scaffold angular reactive form from UI. Quick Notes App &amp; Code Snippet Love to work on new technologies. Just started working on a raspberry pi &amp; react-native. Basically, work with #ionic, AngularJS, Angular2+, Phonegap, Cordova https://about.me/pareshgami

Updated on July 17, 2022

Comments

  • Paresh Gami
    Paresh Gami almost 2 years

    I created following controller with 2 service calling with services. Second response comes before then first. i want to do like i need first response first and second response second. but i just stuck with async and sync please help me for solving.

    Second call is depends on first call. For example if first call returns 10 record then i have to call second web service 10 time taking id from first response. so i use for loop but it is not proper.

    Controller

    var mycompaigndata = [];
    
    asyncService.loadDataFromUrls($http.get(WSURL + 'api/first/', 
    {
        headers: 
        {
            "Authorization":'Bearer <my-token>'
        }
    }))
    .then(function(data)
    {
        console.log(data);
    });
    
    
    asyncService.loadDataFromUrls($http.get(WSURL + 'api/second', 
    {
        headers:
        {
            "Authorization":'Bearer <my-token>'
        }
    }))
    .then(function(data)
    {   
        console.log(data);
    });
    

    Service

    app.service('asyncService', function($http, $q) 
    {
        return {
            loadDataFromUrls: function(url) 
            {
                var deferred = $q.defer();
                var urlCalls = [];
    
                urlCalls.push(url);
    
                $q.all(urlCalls)
                .then(
                function(results) 
                {
                    deferred.resolve(results) 
                },
                function(errors) 
                {
                    deferred.reject(errors);
                },
                function(updates) 
                {
                    deferred.update(updates);
                });
                return deferred.promise;
            }
        };
    });
    
  • Paresh Gami
    Paresh Gami about 8 years
    Second call is depends on first call. For example if first call returns 10 record then i have to call second web service 10 time taking id from first response
  • Paresh Gami
    Paresh Gami about 8 years
    Second call is depends on first call. For example if first call returns 10 record then i have to call second web service 10 time taking id from first response
  • fikkatra
    fikkatra about 8 years
    you can use properties of the 'data' object when doing the second call. However, when you say you need to loop, i.e. do the second call multiple times, you might want to take a look at $q.all. But that's a different question.
  • aseferov
    aseferov about 8 years
    when you write second call in the first call promise the second call will wait for first call and you can use first request data for second request
  • Paresh Gami
    Paresh Gami about 8 years
    Sorry. i forgot to add this on my question. Please can give answer of that?
  • Paresh Gami
    Paresh Gami about 8 years
    Great help. Thank you very much :)