Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

synchronous and asynchronous calling in angularJS with promise and defer

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;
        }
    };
});
like image 852
Paresh Gami Avatar asked Dec 18 '22 17:12

Paresh Gami


2 Answers

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; });
        }
    };
});
like image 60
fikkatra Avatar answered Dec 21 '22 06:12

fikkatra


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);
    });
like image 27
JLRishe Avatar answered Dec 21 '22 07:12

JLRishe