简体   繁体   English

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

[英]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: 它在不同的浏览器中具有不同的值,但是,当较长的命名函数尾部调用较短的命名值时,堆栈跟踪:

  • with TCO: gets shorter, because the stack frame of the outer function gets replaced by the stack frame of the inner function. 使用TCO:变短,因为外部函数的堆栈帧被内部函数的堆栈帧替换。
  • without TCO: gets longer, because the stack frame of the inner function gets appended. 没有TCO:变长,因为内部函数的堆栈帧被追加。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM