Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/474.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node.js尾部调用优化:可能还是不可能?_Javascript_Node.js_Tail Call Optimization - Fatal编程技术网

Javascript 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); 现在,我做了一些挖掘,我发现了。在这里,它似乎说我应该这

到目前为止,我喜欢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 {
        yield foo(x-1);
    }
}

foo(100000);
但是,这给了我语法错误。我尝试过各种排列方式,但在所有情况下,Node.js似乎都不满意某些东西

基本上,我想知道以下几点:

  • Node.js是否执行TCO
  • 在Node.js中,这个神奇的
    产品是如何工作的

  • 这里有两个截然不同的问题:

    • Node.js是否执行TCO
    • 在Node.js中,这个神奇的产品是如何工作的
    Node.js是否有TCO?

    TL;DR从节点8.x开始不再是了。有一段时间,它在一个标志或另一个标志后面,但在撰写本文(2017年11月)时,它不再支持了,因为它使用的底层V8 JavaScript引擎不再支持TCO。更多信息请参见

    详情:

    尾部调用优化(TCO)是必需的。因此,直接支持它并不是NodeJS的事情,而是NodeJS使用的V8 JavaScript引擎需要支持的事情

    从Node 8.x开始,V8不支持TCO,甚至在标志后面也不支持。在将来的某个时候它可能会(再次)这样做;更多信息请参见

    Node 7.10到6.5.0(我的笔记上说是6.2,但不同意)至少在严格模式下支持标志背后的TCO(6.6.0及以上版本中的
    --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 ...