1

I am trying to write a loop which performs a number of http requests and adds each response to a list.

However, I don't think I am going about it quite the right way.

I think I am not implementing the required promises correctly. The console log after the for loop shows myList array as empty.

Code:

var _myList = []

function getStuff() {

    var deferred = $q.defer()

    var url = someUrl

    $http.get(url).success(function(response) {

        if ( response.array.length > 0 ) {

            // loop starts here
            for ( var i=0; i < response.array.length; i++ ) {

                getThing(response.array[i].id);

            };
            // check the varibale here

            console.log(_myList);

            deferred.resolve('Finished');

        } else {

            deferred.resolve('No stuff exists');

        };

    }).error(function(error) {

        deferred.reject(error);

    });

    return deferred.promise;

};

function getThing(thindId) {

    var deferred = $q.defer()

    var url = someUrl + thingId;

      $http.get(url).success(function(response) {

            _myList.push(response);

            deferred.resolve(response);

      }).error(function(error) {

            deferred.reject(error);

      });       

    return deferred.promise;

};
user2085143
  • 4,162
  • 7
  • 39
  • 68
  • [This](http://stackoverflow.com/questions/13951456/using-deferred-with-nested-ajax-calls-in-a-loop) looks promising, just convert $.ajax to $http – Sean C Jan 07 '16 at 18:09
  • Does it matter if they execute in parallel or do you want them to execute in sequence? – jusopi Jan 07 '16 at 18:09

2 Answers2

1

You indeed won't be able to populate _myList array with for-loop like you set up. Instead create an array of promises - one per data item in response.array and return it as inner promise.

function getStuff() {

    var url = someUrl;

    return $http.get(url).then(function(response) {
        if (response.data.array.length > 0) {
            return $q.all(response.data.array.map(function(data) {
                return getThing(data.id);
            }));
        } else {
            return 'No stuff exists';
        }
    });
}

function getThing(thindId) {
    var url = someUrl + thingId;
    return $http.get(url).then(function(response) {
        return response.data;
    });
}

After that you would use getStuff like this:

getStuff().then(function(myList) {
    console.log(myList);
});
dfsq
  • 191,768
  • 25
  • 236
  • 258
  • This looks great, won't get a chance to try it until tomorrow, will let you know how it goes. Quick question; is 'return' in this case used instead of deferred.resolve() ? – user2085143 Jan 07 '16 at 19:30
  • You should not use deferred for this. $http methods already returns promise, so deferred is redundant (deferred anti-pattern). `return` from promise creates new promise to be passed down the chain. – dfsq Jan 07 '16 at 19:36
1

You can simplify your code as follows:

var allThings = response.array.map(function(id){
  var singleThingPromise = getThing(id);
  //return a single request promise
  return singleThingPromise.then(function(){
    //a getThing just ended inspect list
    console.log(_myList);
  })
});
$q.all(allThings).then(function(){
  //only resolve when all things where resolved
  deferred.resolve('Finished');
}, function(e){
  deferred.reject('Something went wrong ' + e);
});
miensol
  • 39,733
  • 7
  • 116
  • 112