AngularJS: chain promises for forEach loop

I'm having trouble wrapping my head around promises. I use the Google Earth API to tour addresses. A tour is just an animation that lasts about a minute, and when it ends, the following should begin.

Here is my function that makes the tour:

var tourAddress = function (address) { return tourService.getLatLong(address).then(function (coords) { return tourService.getKmlForCoords(coords).then(function (kml) { _ge.getTourPlayer().setTour(kml); _ge.getTourPlayer().play(); var counter = 0; var d = $q.defer(); var waitForTour = function () { if (counter < _ge.getTourPlayer().getDuration()) { ++counter; setTimeout(waitForTour, 1000); } else { d.resolve(); } }; waitForTour(); return d.promise; }); }); } 

It seems to work very well. It starts the animation and returns a promise that resolves when the animation is complete. Now I have an array of addresses, and I want to make them for them:

 $scope.addresses.forEach(function (item) { tourAddress(item.address).then(function(){ $log.log(item.address + " complete"); }); }); 

When I do this, they all execute at the same time (Google Earth does the animation for the last address), and they all complete simultaneously. How to connect them to the fire after completing the previous one?

UPDATE

I used @phtrivier great help to achieve it:

  $scope.addresses.reduce(function (curr,next) { return curr.then(function(){ return tourAddress(next.address) }); }, Promise.resolve()).then(function(){ $log.log('all complete'); }); 
+7
javascript angularjs promise angular-promise
source share
2 answers

You are right, the requests are executed immediately because the call to tourAddress (item.address) fulfills the request and returns the promise that was allowed when the request was executed.

Since you call tourAddress in a loop, many Promises are generated, but they are independent of each other.

You want to call tourAdress, take the returned promise, wait for it to be resolved, and then call tourAddress again with a different address, etc.

Manually, you need to write something like:

 tourAddress(addresses[0]) .then(function () { return tourAddress(addresses[1]); }) .then(function () { return tourAddress(addresses[2]); }) ... etc... 

If you want to do this automatically (you are not the first: How can I execute the Promises array in sequential order? ), You could try reducing the address list to a single promise that will fulfill the whole chain.

 _.reduce(addresses, function (memo, address) { return memo.then(function (address) { // This returns a Promise return tourAddress(address); }); }, Promise.resolve()); 

(This is a pseudo code that uses underscores and bluebirds, but it needs to be adapted)

+5
source share

This is because you are doing it asynchronously, so that they will all work simultaneously. This answer should help you rewrite your loop so that each address starts after the next.

Asynchronous loop deferred jQuery (promises)

0
source share

All Articles