[英]Is it possible to detect tail call optimization in WebKit?
I have a recursive function and exhausting the call stack is an issue I run into sometimes. 我有一个递归函数,耗尽调用堆栈是我遇到的问题。 I know I can use streams, promises with setTimeout, but I would like to just write code that triggers tail call optimization. 我知道我可以使用streamTime,使用setTimeout,但我想编写触发尾调用优化的代码。 So far only Webkit seem to have implemented tail call optimization (TCO). 到目前为止,只有Webkit似乎已经实现了尾调用优化(TCO)。 Other than knowing the theory, is there any way do check if my code will trigger TCO, either with devtools or by examining the output of the Webkit compiler? 除了知道理论之外,有没有办法检查我的代码是否会触发TCO,无论是使用devtools还是检查Webkit编译器的输出?
I know it's not perfect, but I think it's the best option we have currently. 我知道它并不完美,但我认为这是我们目前最好的选择。
Consider this function: 考虑这个功能:
"use strict";
function detectTCO() {
const outerStackLen = new Error().stack.length;
// name of the inner function mustn't be longer than the outer!
return (function inner() {
const innerStackLen = new Error().stack.length;
return innerStackLen <= outerStackLen;
}());
}
Error.stack
is not standard, but it has basic support in all modern browsers. Error.stack
不是标准的,但它在所有现代浏览器中都有基本支持。 It has different values in different browsers, nonetheless, when a longer named function tail-calls a shorter named one, the stack trace: 它在不同的浏览器中具有不同的值,但是,当较长的命名函数尾部调用较短的命名值时,堆栈跟踪:
As of now, this returns true
for Safari, and false
for other browsers, which is the current TCO support. 截至目前,这对于Safari返回true
,对于其他浏览器则返回false
,这是当前的TCO支持。
"use strict"; function detectTCO() { const outerStackLen = new Error().stack.length; // name of the inner function mustn't be longer than the outer! return (function inner() { const innerStackLen = new Error().stack.length; return innerStackLen <= outerStackLen; }()); } document.getElementById('result').innerText = detectTCO() ? 'Yes' : 'No';
#result { color: blue; font-weight: bold; }
Is TCO available? <div id="result"></div>
Could utilize .toString()
, RegExp.test()
to check for return
statement followed by underscore, or $ sign , az characters; 可以利用.toString()
, RegExp.test()
来检查return
语句后跟下划线或$ sign,az字符; followed by open parenthesis followed by any characters followed by closing parenthesis 然后是左括号,后跟任何字符,后跟右括号
function forEach(arr, callback, start) { if (0 <= start && start < arr.length) { callback(arr[start], start, arr); return forEach(arr, callback, start + 1); // tail call } } console.log(/return [_a-z$]+\\(.*\\)/i.test(forEach.toString()))
You could always do it in the most idiotic way - run tail recursive function in try, catch block with some "big" arguments. 你总是可以用最愚蠢的方式来做 - 在try中运行tail递归函数,用一些“大”参数来捕获块。 If it throws then TCO is not working. 如果它抛出则TCO不起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.