是否有可能在WebKit中检测尾调用优化?

时间:2015-11-27 03:57:10

标签: javascript optimization webkit tail-recursion

我有一个递归函数并且耗尽调用堆栈是我遇到的一个问题。我知道我可以使用streamTime,使用setTimeout,但我想编写触发尾调用优化的代码。到目前为止,只有Webkit似乎实现了尾调用优化(TCO)。除了了解这个理论之外,有没有办法检查我的代码是否会触发TCO,无论是使用devtools还是检查Webkit编译器的输出?

3 个答案:

答案 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不是标准版,但它在所有现代浏览器中都有基本支持。它在不同的浏览器中具有不同的值,但是,当较长的命名函数尾部调用较短的命名的一个时,堆栈跟踪:

  • 与TCO:变短,因为外部函数的堆栈帧被内部函数的堆栈帧替换。
  • 没有TCO:变长,因为内部函数的堆栈框架会被追加。

截至目前,这将为Safari返回true,为其他浏览器返回false,这是目前的TCO支持。

&#13;
&#13;
"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;
&#13;
&#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不起作用。