0

This is my requirement with AngularJS:

 for (var i = 0, len = self.Scope.data.length; i < len; i++) 
{

         var data = self.Scope.data[i];
         var self = this;
//First asynchronous function
self.EcritureService.createNewData(data).then(() => {
         })                                                     
//Second asynchronous function
self.OperationService.getOperation(data.idOperation).then((operation) => {

         })   
//Third asynchronous function
self.AccountService.getAccount(data.codeCompte).then((compte) => {
               currentAccount = compte;
               currentAccount.montant = currentAccount.montant+data.montant;
         })   
//Fourth one relies on the third result, So it must be executed sequentially
self.AccountService.updateAccount(currentAccount).then(() => {
         })                    
}
// After all fetch loop's promises are resolved I want to execute some instructions here for to update the operation retrieved in the second function.

I want this loop iterator wait till all promises are resolved before going on the next step than make sure that all works are done, moving to last functionality that reside outside the loop bloc

Ahmed Chebbi
  • 9
  • 1
  • 1
  • 8
  • Can you *please* fix your indentation? – Bergi Jun 01 '17 at 00:34
  • JavaScript is single-threaded. The `for` loop will complete **before any** of the promises are resolved. The loop can't be made to wait. – georgeawg Jun 01 '17 at 01:07
  • You can write your logic as if it was synchronous, put it into function, and execute that function via synchronous executor [nsynjs](https://github.com/amaksr/nsynjs). See function "process()" in similar example here: https://github.com/amaksr/nsynjs/blob/master/examples/browser-ajax-seq.js – amaksr Jun 01 '17 at 01:29

2 Answers2

0

Create arrays of promises and use $q.all(promise_array) to run when all promises are resolved

// map array of `$q.all()` promises
let promises = self.Scope.data.map((data) => {
  //First asynchronous function
  let promise_1 = self.EcritureService.createNewData(data).then(() => {})
  //Second asynchronous function
  let promise_2 = self.OperationService.getOperation(data.idOperation).then((operation) => {

  })
  //Third asynchronous function
  let promise_3 = self.AccountService.getAccount(data.codeCompte).then((compte) => {
    currentAccount = compte;
    currentAccount.montant = currentAccount.montant + data.montant;
    return currentAccount;
  }).then((currentAccount) => {
    //return promise of 4th inside `then()` of third
    return self.AccountService.updateAccount(currentAccount).then(() => {});
  });

  // this `$q.all()` resolves when this mapped instance of above all resolve
  return $q.all([promise_1, promise_2, promise_3]);

});

// resolves when all the loop instances of `$q.all()` resolve
$q.all(promises).then(()=>{
  // run completion code here
}).catch(err=>{
  console.log('Something failed in promise chain')
})
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Ha - that is gorgeous :) The array of $q.all's that is then $q.all'ed - love it :) Much better than a recursive loop! – IrishDubGuy Jun 01 '17 at 00:17
0

First off, I would say that you probably don't want those services to be promises, given that you are trying to get around the "promiseness" of them. So the simplest solution would be to rewrite the services to just return normally instead of via a promise.

But to answer your questions. Second part first - the easiest way to link the 4th promise to the 3rd is just to put it inside the 3rd .then, like this:

//Third asynchronous function 
self.AccountService.getAccount(data.codeCompte).then((compte) => {
           currentAccount = compte;
           currentAccount.montant = currentAccount.montant+data.montant; 
           //Fourth one relies on the third result, So it must be executed sequentially
           self.AccountService.updateAccount(currentAccount).then(() => {
     })  
 })

If you put any error handling in then you might decide to put the nested promise in a .finally clause instead.

As for getting the loop to wait, for loops really aren't designed to do that. The easiest way to achieve that would to write your own loop and use $q.all to group together the promises. You would need to keep track of a loop counter, which you increment in the .then of $q.all and use a recursive function that breaks out when the required number of loops is done.

IrishDubGuy
  • 1,053
  • 2
  • 9
  • 18