我有一个递归函数并且耗尽调用堆栈是我遇到的一个问题。我知道我可以使用streamTime,使用setTimeout,但我想编写触发尾调用优化的代码。到目前为止,只有Webkit似乎实现了尾调用优化(TCO)。除了了解这个理论之外,有没有办法检查我的代码是否会触发TCO,无论是使用devtools还是检查Webkit编译器的输出?
答案 0 :(得分:6)
我知道它并不完美,但我认为这是我们目前最好的选择。
考虑这个功能:
"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
不是标准版,但它在所有现代浏览器中都有基本支持。它在不同的浏览器中具有不同的值,但是,当较长的命名函数尾部调用较短的命名的一个时,堆栈跟踪:
截至目前,这将为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';
&#13;
#result {
color: blue;
font-weight: bold;
}
&#13;
Is TCO available?
<div id="result"></div>
&#13;
答案 1 :(得分:1)
可以利用.toString()
,RegExp.test()
检查return
语句后跟下划线或$ sign,a-z字符;然后是左括号,后跟任何字符,后跟右括号
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()))
答案 2 :(得分:0)
你总是可以用最愚蠢的方式做到这一点 - 在try中运行tail递归函数,用一些&#34; big&#34;参数。如果它抛出则TCO不起作用。