语言:JavaScript
递归 - 不是我最喜欢的主题.
承诺 - 他们可能会混淆.
递归+承诺 - 我需要在一个带衬垫的房间里编程.
我制作了这个小小的JS Fiddle拼图,我把RecursiveFunHouse称为通过将问题简化为愚蠢而保持理智的喜剧方式.希望yall可以从我的痛苦中笑出来:)
问题:
每个递归调用都依赖于前一个调用的结果,但为了获得结果,我必须运行异步任务并在其他子任务中使用该结果.
"Recursive Fun House"帮助我将问题归结为此 - 原始递归循环继续使用未定义的值,因为子任务仍在执行.
Fun House - 围绕收集(-99)和99之间的随机数循环.一旦最后一个数字和新数字之间的最后一个差异是积极的,乐趣就结束了
打印"在这里制作1 ...在这里制作6"应该表明子任务处理正确,我们有一个下一个循环的值.
目前它打印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注意 - 原谅我可怜的回复声明
return num;
它只是显示了我希望我可以告诉我的电脑.关于递归和承诺的问题:
1)我是否应该首先担心进入下一个递归循环并且承诺尚未解决?
2)如果没有,那么保持此函数分解并强制每个递归循环等待最后一次调用的解决方法的干净方法是什么?
递归和承诺有时似乎是向导级别的95神奇...这就是我所说的.问-完成.
1> traktor53..:在经典的同步递归中,递归状态存储在推送和弹出公共执行堆栈的堆栈帧中.在异步递归中,递归状态可以存储在推送的Promise对象中,并从公共的promise链中弹出.例如:
function asyncThing( asyncParam) { // something async returning a promise return new Promise( function( resolve, reject) { function timeOut() { resolve( asyncParam); // resolve with parameter value passed } setTimeout( timeOut, 1000); }); } function recFun( num) { // asynchronous recursive function // do whatever synchronous stuff when called // ... function decide( asyncResult) { // process async result and decide what to do // do something with asyncResult console.log("asyncResult: " + asyncResult); if( asyncResult == 0) console.log("ignition"); // decide if further recursion needed if( asyncResult < 0) return "lift off"; // all done return recFun( num-1); // not all done, recurse } // return a promise resolved by doing something async and deciding what to do with it // to be clear the returned promise is the one returned by .then 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);});运行代码以查看其效果.
这个例子依赖的核心原则(魔术):
then
监听器函数的注册返回一个待处理的promise.如果调用侦听器并从执行返回,则侦听器返回值将解析挂起的promise.如果侦听器抛出错误而不是返回,则使用抛出的值拒绝挂起的promise.诺言不能兑现承诺.如果一个监听器返回一个promise,它会在从监听器注册返回的promise之前插入到promise链的剩余部分的头部.来自侦听器注册的承诺(以前是剩余承诺链的负责人)然后与插入的承诺同步,在最终结算时采用其状态和值.
当定义链的代码执行时,所有承诺链的承诺对象和链接都是同步创建的.然后定义代码运行完成(意味着它返回事件循环而不会被异步回调中断,因为JavaScript是单线程的).
如果和何时执行侦听器函数(因为一个promise已经完成或被拒绝),它们将在事件循环中自己调用异步执行,导致执行侦听器的代码本身运行完成.
这意味着在注册promise侦听器(通过调用)时所做的所有日志条目都
then
出现在侦听器函数中的任何日志条目之前,异步执行一段时间之后.承诺不涉及时间旅行.这会让你的头疼吗?也许不是,但至少它是真的.
`
2> Supersharp..:如评论中所述,您必须稍微修改
performSideTasks
以使其返回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()
在main函数的方法中使用异步结果.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
@Supersharp:我注意到你对我看过的大多数代码使用了不同的[缩进样式](https://en.wikipedia.org/wiki/Indent_style).这不一定是坏事,但是要小心你选择的风格 - 由于Javascript中的[自动分号插入](http://bonsaiden.github.io/JavaScript-Garden/#core.semicolon),它可能会导致你意外的错误.