1

I need to wait for several promises to finish before executing some code (angularJS):

var promises = [calculationPromise1, calculationPromise2];
$q.all(promises)
   .then(function(){
        notifyUser("I am done calculating!");
    });

In my case the user will be able to add new calculations at any time though. So if he adds a new calculation, the notification should be delayed further.

Modify the initial array

Sadly $q.all does not listen for changes on the promise-array, so executing this does not have any effect:

promises.push(newCalc);

Create a new $q.all-promise

This does not work either, because the notification will be shown multiple times instead of being delayed:

var promises = [calculationPromise1, calculationPromise2];
var qAllPromise; 

qAllPromise = $q.all(promises)
   .then(function(){
         notifyUser("I am done calculating!");
    })

function addAnotherCalculation(calc){
   qAllPromise = $q.all([calc, qAllPromise])
     .then(function(){
         notifyUser("I am done calculating!");
     })
}    

recursive call

recursively calling $q.all and executing the .then block only once should work:

var promises = [calculationPromise1, calculationPromise2];

function notifyWhenDone() {
$q.all(promises)
   .then(function() {
      if(allPromisesResolved()){
          notifyUser("I am done calculating!");
      }
      else {
          notifyWhenDone();
      }
    })
}

function addAnotherCalculation(calc){
   promises.push(calc);
}

My problem with this is that angular does not offer an API to check the status of promises which i would need in an allPromisesResolved function. I could check for promise.$$state.status === 1 to identify resolved promises, but i would rather not use internal variables ($$state) if i don't have to.

Question

Is there an easy way to add promises to a $q.all promise or can you think of an alternative solution to wait for a dynamically growing number of promises?

H W
  • 2,556
  • 3
  • 21
  • 45
  • 2
    `allPromisesResolved` doesn't make sense because all promises are resolved by definition if you are in `then` callback. I think promises are the wrong pattern for what you are trying to achieve. – dfsq Sep 09 '16 at 08:53
  • I don't really have a choice whether or not to use promises since those are the tool to handle async calls. The choice to use `$q.all` however is debatable - it just felt intuitive to me. – H W Sep 09 '16 at 09:16
  • To clarify: the intention of a methode `allPromisesResolved` is to check if actually ALL promises are resolved that are relevant currently. This is different from the condition that causes `then` to execute because new promises/calculations may have been added after `$q.all` was called and before `.then` gets executed. – H W Sep 09 '16 at 09:18
  • What do you want to happen if the user adds another promise after `allPromisesResolved` is already fulfilled? – Bergi Sep 09 '16 at 10:26
  • that is the condition which stops the recursive call. `allPromisesResolved` should just return `true` or `false` depending on the current state of the promises in the array `promises` – H W Sep 09 '16 at 11:02
  • 1
    Have a look at [this answer](http://stackoverflow.com/a/37819138/1048572) then – Bergi Sep 09 '16 at 12:24
  • Possible duplicate of [How to know when all Promises are Resolved in a dynamic "iterable" parameter?](http://stackoverflow.com/questions/37801654/how-to-know-when-all-promises-are-resolved-in-a-dynamic-iterable-parameter) – Jeff Bowman Sep 09 '16 at 18:13
  • I would steer you towards observables... https://github.com/Reactive-Extensions/RxJS – bluetoft Sep 11 '16 at 01:40

1 Answers1

4

You can accomplish this with recursion. You can empty your promises array each time you call $q.all() and then check whether it has any new values when you get to the then() handler:

var promises = [calculationPromise1, calculationPromise2];

function waitForPromises(completedSoFar) {
    var p = $q
        .all((completedSoFar || []).concat(promises))
        .then(function (results) {
             return promises.length
                 ? waitForPromises(results)
                 : results;
        });

    promises = [];

    return p;
}

waitForPromises().then(function (results) {
    // all done
});
JLRishe
  • 99,490
  • 19
  • 131
  • 169