在NodeJS中的尾recursion

所以我最近碰到的情况下,我需要编写的代码,callback调用自己等等,并想知道NodeJS和尾调用支持,所以我发现这个答案https://stackoverflow.com/a/30369729说,是的,它是支持的。

所以我尝试了这个简单的代码:

"use strict"; function fac(n){ if(n==1){ console.trace(); return 1; } return n*fac(n-1); } fac(5); 

使用Linux x64上的Node 6.9.2并将其作为node tailcall.js --harmony --harmony_tailcalls --use-strict ,结果为:

 Trace at fac (/home/tailcall.js:4:11) at fac (/home/tailcall.js:7:11) at fac (/home/tailcall.js:7:11) at fac (/home/tailcall.js:7:11) at fac (/home/tailcall.js:7:11) at Object.<anonymous> (/home/tailcall.js:10:1) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) 

这清楚地显示了调用堆栈充满了调用,并且不支持尾recursion,虽然我使用了最新的NodeJS。

NodeJS / JavaScript是否支持tail-recursion? 或者我真的不得不与发电机和产量,但问题是我的callback会严重asynchronous,我不会用返回值无论如何,我只需要确保调用堆栈没有得到无用的填充函数调用是指本身作为回报。

首先,如果你关心的实际情况是函数调用自己的asynchronouscallback函数,那么你可能没有任何堆栈堆积。

这是因为在调用asynchronouscallback之前,原始函数已经返回并且整个堆栈解开,所以尽pipe它在外观上看起来像recursion,但是没有构build堆栈。

下面是一个简单的代码示例,在这个示例中,一个函数从asynchronouscallback中调用自己,并且没有堆栈堆积。

 function getPages(baseURL, startParam, endParam, progressCallback) { function run(param) { request(baseURL + param, function(err, response, body) { if (err) return progressCallback(err); ++param; if (param < endParam) { progressCallback(null, body); // run another iteration // there is no stack buildup with this call run(param); } else { // indicate completion of all calls progressCallback(null, null); } }); } run(startParam); } 

先前的run()调用已经返回,并且在asynchronouscallback被调用之前堆栈已经完全展开,所以当这看起来像recursion时,没有堆积累。


在你展示的特定代码中,你可以完全避免使用while循环来重写这个recursion,这个循环可以在任何版本的Javascript中有效地工作:

 function fac(n){ var total = 1; while (n > 1) { total *= n--; } return total; } // run demo in snippet for (var i = 1; i <= 10; i++) { console.log(i, fac(i)) } 

你有什么不是一个尾巴。 尾调用是作为另一个函数的最后一个动作执行的函数调用。 除了函数调用本身之外,尾recursion调用是相同的。

但是,您的代码的最后一个行为是n*fac(n-1) ,而不是fac(n-1) 。 这不是一个recursion尾调用,因为当计算recursion调用时,当前栈仍然需要记住n ,所以它将知道要乘以哪些数字。

你可以做的是计算这个信息1步之前:

 const fac = (n, result = 1) => n === 1 ? result : fac(n - 1, n * result); console.log(fac(5)); // 120 

我不确定你的recursion函数是否有尾部调用。 可能是你可以尝试以下;

 "use strict"; var fac = (n, r = 1) => n === 1 ? r : (r *= n, fac(n-1,r)); console.log(fac(5)); 
Interesting Posts