简体   繁体   English

Javascript尾递归

[英]Javascript tail recursion

Why the following code runs so.... slow....... ? 为什么以下代码如此运行.....慢....?

<html><body><script type="text/javascript">
    var i = 0;

    f();

    function f() {
        if (i == 5000) {
            document.write("Done");
        } else {
            i++;
            tail();
        }
    }

    function tail() {
        var fn = tail.caller;
        var args = arguments;
        setTimeout(function() {fn.apply(this, args)}, 0);
    };

</script></body></html>

A couple of reasons: 有两个原因:

  1. Using the caller property on a function object introduces overhead (and is non-standard) 在函数对象上使用caller属性会带来开销(并且是非标准的)

  2. The same for using the arguments pseudo-array (IIRC, this will slow down a function call by a factor of 2-5, depending on which browser you're using) 使用arguments伪数组的方式相同(IIRC,这将使函数调用的速度降低2-5倍,具体取决于您使用的浏览器)

  3. setTimeout will typically take no less than 10ms to call your function back (although Chrome sometimes goes a bit faster than that), even when you specify 0 as the timeout. setTimeout通常将花费不少于 10ms的时间来回调您的函数(尽管Chrome有时会更快一些),即使您将超时指定为0。 This will probably be the biggest reason: 5,000 iterations at ~10ms is 50 seconds. 这可能是最大的原因:〜10ms处的5,000次迭代为50秒。

That last item is the reason I said: 最后一项是我说的原因:

If you have a lot of loop iterations (eg, a couple of hundred instead of 15), it may well be worth doing a chunk of them on each iteration rather than yielding on each iteration; 如果您有很多循环迭代(例如,几百个而不是15个),那么在每次迭代中进行一小部分而不是在每次迭代时都屈服可能是值得的。 the yield takes a measureable time (typically ~10-15ms). 产量需要一个可测量的时间(通常〜10-15ms)。

...in my answer to your other recent question . ...在我对您最近的其他问题的回答中

Note that your code can be rewritten without using caller or arguments , making it much clearer: 请注意,您可以在不使用callerarguments情况下重写代码,从而使代码更加清晰:

var i = 0;

f();

function f() {
    if (i == 5000) {
        document.write("Done");
    } else {
        i++;
        setTimeout(f, 0);
    }
}

Separately: I notice you used document.write in your code sample. 另外:我注意到您在代码示例中使用了document.write If you're doing this with code executed during the page parse (which is the only place you can use document.write ), rather than in code you trigger with an event handler after the page is parsed, you can't use setTimeout . 如果使用页面解析期间执行的代码(这是可以使用document.write的唯一位置)来执行此操作,而不是使用解析页面后使用事件处理程序触发的代码,则不能使用setTimeout This is because code that ouputs via document.write has to run synchronously with the HTML parser on page load. 这是因为通过代码OUPUTS document.write 必须与页面加载HTML解析器同步运行。 Script blocks are executed during the parse for exactly this reason: In case they emit HTML the parser has to deal with. 正是由于以下原因,脚本块在解析期间执行:如果它们发出HTML,则解析器必须处理。 If you want to modify the page after parsing (which I'd recommend), you want to use DOM methods to get an element reference, and then either use DOM methods to add to it or (and this is both easier and faster running) set the innerHTML property on the element. 如果要解析修改页面(我建议这样做),则要使用DOM方法来获取元素引用,然后使用DOM方法来添加该页面,或者(这既容易又快速地运行)在元素上设置innerHTML属性。

My sense from both questions is that you probably do want to be looking into web workers , and only using the above for fallback for browsers that don't support them yet (IE, I'm afraid, but I bet IE9 will have them — and all the other major ones have them now). 从这两个问题中我的感觉是,您可能确实希望研究Web worker ,并且仅对不支持它们的浏览器使用以上内容(我担心IE9,但我敢打赌IE9会拥有它们-其他所有主要的对象现在都有)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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