Javascript 引擎中的尾调用优化实现
Tail Call Optimization implementation in Javascript Engines
截至 2019 年 2 月 Chrome 版本 71.0.3578.98
Mac
,以下程序在 16516
.
的计数处抛出 Uncaught RangeError: Maximum call stack size exceeded error.
const a = x => {
console.log(x)
a(x + 1)
}
a(1)
我用谷歌搜索了很多,但没能找到任何讨论 Chrome 或其他浏览器对尾调用优化 (TCO) 的支持或任何未来实施计划的文章。
我的两个问题是:
- 目前 Chrome 或任何其他浏览器或 Javascript 引擎是否支持 TCO
- 是否有计划在不久的将来在任何 Javascript 引擎中实施 TCO
我发现的帖子大多是旧的(2016 年或更早的)或只是令人困惑。例如https://www.chromestatus.com/feature/5516876633341952
即使 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);
TCO,或者更确切地说,JavaScript 中的 Tail Call Elimination——在讨论中也经常被称为适当的尾调用 (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 关注开发人员从堆栈跟踪调用 "missing" 的体验(这个问题已在 2011 年进行了详细讨论)。
为了在挽救尾调用功能的同时解决其中一些问题,包括 Chrome 和 Edge 团队在内的一些成员提议进行尾调用 explicit,即要求 return 语句用附加关键字注释以选择尾调用语义。这些 so-called“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 中仍然可用。
披露:我是 TC39 和 Chrome/V8 团队的成员,直到 2017 年,所以我的观点可能有偏见。
截至 2019 年 2 月 Chrome 版本 71.0.3578.98
Mac
,以下程序在 16516
.
Uncaught RangeError: Maximum call stack size exceeded error.
const a = x => {
console.log(x)
a(x + 1)
}
a(1)
我用谷歌搜索了很多,但没能找到任何讨论 Chrome 或其他浏览器对尾调用优化 (TCO) 的支持或任何未来实施计划的文章。
我的两个问题是:
- 目前 Chrome 或任何其他浏览器或 Javascript 引擎是否支持 TCO
- 是否有计划在不久的将来在任何 Javascript 引擎中实施 TCO
我发现的帖子大多是旧的(2016 年或更早的)或只是令人困惑。例如https://www.chromestatus.com/feature/5516876633341952
即使 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);
TCO,或者更确切地说,JavaScript 中的 Tail Call Elimination——在讨论中也经常被称为适当的尾调用 (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 关注开发人员从堆栈跟踪调用 "missing" 的体验(这个问题已在 2011 年进行了详细讨论)。
为了在挽救尾调用功能的同时解决其中一些问题,包括 Chrome 和 Edge 团队在内的一些成员提议进行尾调用 explicit,即要求 return 语句用附加关键字注释以选择尾调用语义。这些 so-called“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 中仍然可用。
披露:我是 TC39 和 Chrome/V8 团队的成员,直到 2017 年,所以我的观点可能有偏见。