admin管理员组文章数量:1178529
Language: JavaScript
Recursion - Not my Favorite Topic.
Promises - They can get confusing.
Recursion + Promises - I need to program in a padded room.
I made this little JS Fiddle puzzle I call The RecursiveFunHouse as comedic way of keeping my sanity by simplifying the issue into something silly. Hopefully yall can get a laugh out of my pain :)
The Problem:
Each recursive call is dependent on the outcome of the previous call, but in order to get the outcome I must run an asynchronous task and use that outcome in other sub tasks.
The "Recursive Fun House" helped me boil down the issue to this - the original recursive loop is continuing on with an undefined value as the sub tasks are still executing.
The Fun House - loops around collecting random numbers between (-99) and 99. Once the last difference between the last number and the new number is positive the fun is over
Printing "Made it here 1...Made it here 6" should indicate that the sub-tasks were handled correctly and we have a value for the next loop.
Current it prints 1,2,3,6,4,5 :(
recursiveFunHouse.js
var recursiveFunHouse = function(num){
console.log("Made it here 1");
var newNum = performSideTasks();
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]);
}
}
};
var performSideTasks = function(){
console.log("Made it here 2");
someAsyncTask().then(function(num){
anotherTask(num);
console.log("made it here 5");
return num;
});
}
var someAsyncTask = function(){
return new Promise (function(resolve, reject) {
console.log("made it here 3");
var randNum = Math.floor(Math.random()*99) + 1;
randNum *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
setTimeout(function() {
numList.push(randNum)
resolve(randNum)
}, 100);
});
}
var anotherTask = function(num){
console.log("made it here 4");
console.log(num);
};
var numList= [];
recursiveFunHouse(20);
Note - Forgive my pathetic return statement return num;
It just shows what I wish I could tell my computer.
Questions About Recursion and Promises:
1) Should I be worried in the first place about going into the next recursive loop with a promise not yet resolved?
2) If not, what is a clean way to keep this function decomposition and force each recursive loop to wait for the resolution of the last call?
Recursion and Promises can seem wizard-level-95 magical sometimes... that's all I'm saying. Question-Done.
Language: JavaScript
Recursion - Not my Favorite Topic.
Promises - They can get confusing.
Recursion + Promises - I need to program in a padded room.
I made this little JS Fiddle puzzle I call The RecursiveFunHouse as comedic way of keeping my sanity by simplifying the issue into something silly. Hopefully yall can get a laugh out of my pain :)
The Problem:
Each recursive call is dependent on the outcome of the previous call, but in order to get the outcome I must run an asynchronous task and use that outcome in other sub tasks.
The "Recursive Fun House" helped me boil down the issue to this - the original recursive loop is continuing on with an undefined value as the sub tasks are still executing.
The Fun House - loops around collecting random numbers between (-99) and 99. Once the last difference between the last number and the new number is positive the fun is over
Printing "Made it here 1...Made it here 6" should indicate that the sub-tasks were handled correctly and we have a value for the next loop.
Current it prints 1,2,3,6,4,5 :(
recursiveFunHouse.js
var recursiveFunHouse = function(num){
console.log("Made it here 1");
var newNum = performSideTasks();
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]);
}
}
};
var performSideTasks = function(){
console.log("Made it here 2");
someAsyncTask().then(function(num){
anotherTask(num);
console.log("made it here 5");
return num;
});
}
var someAsyncTask = function(){
return new Promise (function(resolve, reject) {
console.log("made it here 3");
var randNum = Math.floor(Math.random()*99) + 1;
randNum *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
setTimeout(function() {
numList.push(randNum)
resolve(randNum)
}, 100);
});
}
var anotherTask = function(num){
console.log("made it here 4");
console.log(num);
};
var numList= [];
recursiveFunHouse(20);
Note - Forgive my pathetic return statement return num;
It just shows what I wish I could tell my computer.
Questions About Recursion and Promises:
1) Should I be worried in the first place about going into the next recursive loop with a promise not yet resolved?
2) If not, what is a clean way to keep this function decomposition and force each recursive loop to wait for the resolution of the last call?
Recursion and Promises can seem wizard-level-95 magical sometimes... that's all I'm saying. Question-Done.
Share Improve this question asked Jan 10, 2016 at 22:14 Nick PinedaNick Pineda 6,46211 gold badges50 silver badges69 bronze badges 1- performSideTasks should return the someAsynTask Promise itself, so that the main function can get the num value inside .then() – Supersharp Commented Jan 10, 2016 at 22:42
2 Answers
Reset to default 28In 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.
`
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] )
}
}
} )
}
本文标签: recursionJavaScriptCalling Recursive Functions With PromisesStack Overflow
版权声明:本文标题:recursion - JavaScript : Calling Recursive Functions With Promises - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738035341a2052862.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论