Javascript Node.js尾部调用优化:可能还是不可能?
到目前为止,我喜欢JavaScript,并决定使用Node.js作为我的引擎,部分原因是Node.js声称它提供了TCO。但是,当我尝试使用Node.js运行此(显然是尾部调用)代码时,它会导致堆栈溢出:Javascript Node.js尾部调用优化:可能还是不可能?,javascript,node.js,tail-call-optimization,Javascript,Node.js,Tail Call Optimization,到目前为止,我喜欢JavaScript,并决定使用Node.js作为我的引擎,部分原因是Node.js声称它提供了TCO。但是,当我尝试使用Node.js运行此(显然是尾部调用)代码时,它会导致堆栈溢出: function foo(x) { if (x == 1) { return 1; } else { return foo(x-1); } } foo(100000); 现在,我做了一些挖掘,我发现了。在这里,它似乎说我应该这
function foo(x) {
if (x == 1) {
return 1;
}
else {
return foo(x-1);
}
}
foo(100000);
现在,我做了一些挖掘,我发现了。在这里,它似乎说我应该这样写:
function* foo(x) {
if (x == 1) {
return 1;
}
else {
yield foo(x-1);
}
}
foo(100000);
但是,这给了我语法错误。我尝试过各种排列方式,但在所有情况下,Node.js似乎都不满意某些东西
基本上,我想知道以下几点:
产品是如何工作的
这里有两个截然不同的问题:
- Node.js是否执行TCO
- 在Node.js中,这个神奇的产品是如何工作的
--harmony
,早期版本中的--harmony\u tailcalls
)
如果您想检查安装,以下是测试使用(如果您使用的是相关版本,请确保使用该标志):
具有此输出的:
0
1
2
3
4
v
对应于我们上一个示例中的state.value
,for of执行所有it.next()
调用并done
为我们检查。node.js从2016年5月17日起最终支持TCO
它需要使用
--使用strict--harmony tailcalls
标志来执行,TCO才能工作。更简洁的答案。。。如前所述,截至其实施日期
TCO有效。它不是防弹的,但很体面。这里是阶乘(7000000,1)
这里没有TCO
>node -e "'use strict';function f(n,t){return n===1?t:f(n-1,n*t);}; console.log(f(15669,1))"
[eval]:1
function f(n,t){return n===1?t:f(n-1,n*t);}; console.log(f(15669,1))
^
RangeError: Maximum call stack size exceeded
at f ([eval]:1:11)
at f ([eval]:1:32)
at f ([eval]:1:32)
at ...
但它确实一直到15668年
至于收益率,请参见其他答案。应该是一个单独的问题
6.2.0-带有“严格使用”和“和谐”
仅适用于10000次小尾优化递归(如问题中所述),但函数调用自身9999999999次失败
7.2.0带有“严格使用”和“和谐”
flag即使在99999999999999调用中也能无缝快速地工作。使用
--harmony
标志运行节点,查看第二个版本的工作方式。e、 g.节点——harmony mytest.js
。但是,首先再看看你举的例子,你只是根据你的情况修改了其中的一部分。关于TCO,真正的问题是V8是否已经实现了它——在我看到的文章中还没有提到这一点。@巴里·约翰逊:我在第二个链接中尝试使用yield
复制示例函数,Node.js对函数*
表示异议。这就是我感到困惑的原因之一。这就是为什么我说您需要使用--harmony选项运行节点。生成器是ES6/Harmony的一部分,这不是默认的节点。链接页面上的任何地方都没有“tail”或“TCO”,您可以链接到宣布tail call支持的内容吗?(支持,我检查过了)也注意到,<>代码>使用严格的< /代码>不需要启用它,只是<代码> -TraceTrace:。还要注意,它背后的原因是V8团队不认为它是稳定的,更不用说做了。它们仍然(如V6 .2.2节点中的V8)在PrimeS.@ T.J.CuuldRead中考虑它:虽然不被认为是稳定的,但到目前为止,它对于ME..T.J.Cuuld:这是第一个具有此标志的版本工作得很好。它的变更日志项是V8Yep的升级。为了让CPU烧坏,将其额外增加了几个数量级。请将}和while放在同一行-对我来说似乎更清楚-无法编辑此内容-因为更改2个字符不足以进行编辑…@AndyS:纯样式编辑在任何情况下都不合适。99999999999999?那是很多电话。。它是否以某种方式优化了计算?
"use strict";
function* counter(from, to) {
let n = from;
do {
yield n;
}
while (++n < to);
}
let it = counter(0, 5);
for (let state = it.next(); !state.done; state = it.next()) {
console.log(state.value);
}
0
1
2
3
4
"use strict";
function* counter(from, to) {
let n = from;
do {
yield n;
}
while (++n < to);
}
for (let v of counter(0, 5)) {
console.log(v);
}
>node --harmony-tailcalls -e "'use strict';function f(n,t){return n===1?t:f(n-1,n*t);}; console.log(f(7000000,1))"
Infinity
>node -e "'use strict';function f(n,t){return n===1?t:f(n-1,n*t);}; console.log(f(15669,1))"
[eval]:1
function f(n,t){return n===1?t:f(n-1,n*t);}; console.log(f(15669,1))
^
RangeError: Maximum call stack size exceeded
at f ([eval]:1:11)
at f ([eval]:1:32)
at f ([eval]:1:32)
at ...