【问题标题】:Tail Call Optimization implementation in Javascript EnginesJavascript 引擎中的尾调用优化实现
【发布时间】:2019-07-10 04:48:23
【问题描述】:

截至 2019 年 2 月,Mac 上的 Chrome 版本 71.0.3578.98 ,以下程序将Uncaught RangeError: Maximum call stack size exceeded error. 抛出16516

const a = x => {
  console.log(x)
  a(x + 1)
}

a(1)

我在谷歌上搜索了很多,但找不到任何文章讨论 Chrome 或其他浏览器对尾调用优化 (TCO) 的支持或任何未来实施它的计划。

我的两个问题是:

  1. Chrome 或任何其他浏览器或 Javascript 引擎目前是否支持 TCO
  2. 是否有计划在不久的将来在任何 Javascript 引擎中实施 TCO

我发现的帖子大多是旧的(2016 年或更早)或只是令人困惑。例如https://www.chromestatus.com/feature/5516876633341952

【问题讨论】:

标签: javascript firefox chromium v8


【解决方案1】:

即使 TCO 似乎对我们所有人来说都是白日梦,通过使用trampoline 技术,您可以轻松地将您的代码转换为运行,就好像它正在被尾部优化一样。

const a = x => {
  if(x > 500000) {
      console.log(x);
      return; 
  }
  return ()=> a(x + 1); //you return a function, it hasn't been called yet
}

const trampoline = fn => (...args) => {
  let result = fn(...args)
  //repeatedly call the function till you hit your base case
  while (typeof result === 'function') {
    result = result();
  }
  
  return result;
}

var t = trampoline(a);
t(1);

【讨论】:

    【解决方案2】:

    TCO,或者更确切地说,JavaScript 中的尾调用 消除——在讨论中也经常被称为正确尾调用 (PTC)——是一个漫长而悲伤的故事。

    大约在 2011 年,TC39(JavaScript 标准委员会)决定在所有主要浏览器供应商的共识下,为即将到来的 ES6 标准采用强制性 TCE。

    2015 年,正式采用了新标准,名称为 EcmaScript 2015。此时,还没有浏览器真正实现 TCE,主要是因为 ES2015 中有太多被认为更重要的新功能要退出。 (今天的 JS 特性提议及其采用流程,包括在生产引擎中的两个实现的要求,对于 ES6 尚不存在。)

    在 2016 年初,Safari 和 Chrome 都实现了 TCE。 Safari 宣布发货,而 Chrome 将其保留在实验功能标志后面。其他浏览器(Firefox 和 Internet Explorer / Edge)也开始研究它并重新考虑。讨论发展了这是否是一个可行的功能。 Edge 在为 Windows ABI 高效实现它时遇到了问题,Firefox 担心堆栈跟踪中调用“丢失”的开发人员体验(这个问题已经在 2011 年详细讨论过)。

    为了在挽救尾调用功能的同时解决其中一些问题,包括 Chrome 和 Edge 团队在内的一些成员提议进行尾调用显式,即要求返回语句是使用附加关键字进行注释以选择尾调用语义。这些所谓的“syntactic tail calls”(STC)是在 Chrome 中实现的,作为概念验证。

    在 2016 年 5 月的 TC39 会议上,尾声问题被广泛讨论了几乎一整天,但没有任何解决方案。 Firefox 和 Edge 明确表示他们不会按照标准中的规定实施 TCE。 Firefox 成员提议将其删除。 Safari 和 Chrome 不同意这一点,Safari 团队明确表示他们无意取消 TCE。语法尾调用的提议也被拒绝了,尤其是 Safari。委员会陷入了僵局。你可以阅读meeting notes of this discussion

    据我所知,从技术上讲,这种僵局今天仍然存在。但实际上,JavaScript 的尾调用几乎已经死了,而且还不清楚它们是否会再次出现。至少这是 Chrome 团队在灾难性会议后得出的结论,这导致决定从 Chrome 中删除尾调用的实现,以简化引擎并防止比特腐烂。它们在 Safari 中仍然可用。

    披露:在 2017 年之前,我一直是 TC39 和 Chrome/V8 团队的成员,因此我的观点可能存在偏见。

    【讨论】:

    • 不错的答案!您可能想在 ES6 Tail Recursion Optimisation Stack OverflowWhy do no javascript engines support tail call optimization? 重新发布它 - 我考虑将其作为重复项关闭
    • 感谢您的精彩回答。非常感谢!
    • (可悲)非常说明性的答案。仅供参考,值得一提的是,有一个经过彻底测试的库github.com/glathoud/fext,它可能是蹦床等模式的一个很好的替代品
    • @Tom,我不会说破坏,但最终是微软和 Mozilla 都明确表示他们不想实施它们,正如我在回答中提到的那样。
    • “句法尾调用”将是一个很好的补充——任何支持 PTC 的语言都将受益于有一些句法方式来标记开发人员使用尾调用递归的意图,以帮助未来的维护者不要不小心重构了优化。
    猜你喜欢
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 2015-04-23
    • 2011-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多