Question

I have a async function, which can recurse into itself.

I'm adding jQuery deferreds to an array each time the function runs, an use $.when() to check if all promises have resolved. My issue is that I can't seem to do this without an arbitary timeout, as I simply don't know when the function stops recursing and adding new promises.

Was it helpful?

Solution

Do push to promises only synchronously, so that you know when you are finished. Since your function is recursive and returns a promise, you can just use the result promises of the recursive calls for this. Use $.when() only for the results of the current recursion level, not for all promises in the call stack.

Also check my answers to Understanding promises in node.js for recursive function and Is there an example of using raw Q promise library with node to recursively traverse a directory asynchronously? - even though they're not using jQuery's implementation, they should give you an idea of how to do it.

OTHER TIPS

Just to add to what Bergi said, and to clarify the underlying issue:

There is no way to know when no more promises will be chained to a promise with .then. Just like there is no way to know from a function where it returns:

myPromise().then(function(vale){
        // I have no easy way to know when handlers will no longer be added to myPromise
        // from myPromise itself
});

Is just like:

 function mySynchronousFunction(){
      // I can't easily tell from here where this code returns or how many time it will
      // be called in the entire program lifecycle.
 };

How would you solve that problem with synchronous code? You probably wouldn't have it in the first place. You'd know better than to rely on global program state and the caller inside a function :)

It's similar to promises. You don't rely on when the last handler was added in promise code.

Instead, what you want to do is call $.when on the inner promises inside the .forEach in your practical example which would give you a hook on when they're all done, and only resolve them in turn when their inner promises resolve - which is just returning them really since promises unwrap recursively.

In addition to Bergi's samples which are all good - see Petka's implementation which should give you the general idea :)

Good luck.


As a side note - you're not really using promises as promise at all. You're more using them as callbacks. If you want a promise to wait for another promise to complete, you can use .then:

promiseReturning1().then(promiseReturning2).then(promiseReturning3).then(function(lastResult){
       // all done here
});

Instead of implementing your own asynchronous queue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top