JavaScript : Calling Recursive Functions With Promises
As stated in the comment, you have to slightly modify performSideTasks
to make it return the Promise:
var performSideTasks = function ()
{
console.log( "Made it here 2" )
return someAsyncTask().then( function ( num )
{
anotherTask(num);
console.log("made it here 5")
return num
} )
}
Then you can use the asynchronous result in the then()
method of the main function.
var recursiveFunHouse = function ( num )
{
console.log( "Made it here 1" )
performSideTasks().then( function ( newNum )
{
console.log( "Made it here 6" )
console.log( "newNum" )
console.log( newNum )
if ( newNum-num > 0 )
{
recursiveFunHouse( newNum )
}
else
{
console.log( "The FunHouse Generated These Numbers :" )
for( var i = 0 ; i <numList.length ; i++ )
{
console.log( numList[i] )
}
}
} )
}
In classical synchronous recursion, recursion state is stored in stack frames pushed and popped off a common execution stack. In asynchronous recursion, recursion state can be stored in Promise objects pushed and popped off the head of a common promise chain. For example:
function asyncThing( asyncParam) { // example operation
const promiseDelay = (data,msec) => new Promise(res => setTimeout(res,msec,data));
return promiseDelay( asyncParam, 1000); //resolve with argument in 1 second.
}
function recFun( num) { // example "recursive" asynchronous function
// do whatever synchronous stuff that recFun does when called
// ...
// and decide what to do with async result: recurse or finish?
function decide( asyncResult) {
// process asyncResult here as needed:
console.log("asyncResult: " + asyncResult);
if( asyncResult == 0)
console.log("ignition");
// check if further recursion is needed:
if( asyncResult < 0)
return "lift off"; // no, all done, return a non-promise result
return recFun( num-1); // yes, call recFun again which returns a promise
}
// Return a promise resolved by doing something async and deciding what to do.
// to be clear the returned promise is the one returned from the .then call
return asyncThing(num).then(decide);
}
// call the recursive function
recFun( 5)
.then( function(result) {console.log("done, result = " + result); })
.catch( function(err) {console.log("oops:" + err);});
Run the code to see its effect.
Core principles (magic) on which this example relies:
then
registration of listener functions returns a pending promise. If a listener is called and returns from execution, listener return value resolves the pending promise. If the listener throws an error instead of returning, the pending promise is rejected with the thrown value.- A promise cannot be fulfilled with a promise. If a listener returns a promise, it is inserted at the head of what remains of the promise chain, before the promise returned from listener registration. The promise from listener registration (previously the head of the residual promise chain) is then synchronized with the inserted promise, adopting its state and value when finally settled.
- All promise objects and linkages for a chain of promises chain are created synchronously when the code defining the chain executes. The definition code then runs to completion (meaning it returns to the event loop without interruption by asynchronous callbacks because JavaScript is single threaded).
If and when listener functions are executed (because a promise becomes fulfilled or rejected) they are executed asynchronously, in their own call out from the event loop, after code which resulted in the listener being executed has itself run to completion.
This means all log entries made when registering promise listeners (by calling then
on a promise) appear before any log entry made by a registered listener function when executed asynchronously at a later time. Promises do not involve time travel.
Will this stop your head hurting? Perhaps not, but at least it's true.
`