简体   繁体   中英

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)

  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)

  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. This will probably be the biggest reason: 5,000 iterations at ~10ms is 50 seconds.

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; the yield takes a measureable time (typically ~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:

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. 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 . This is because code that ouputs via document.write has to run synchronously with the HTML parser on page load. Script blocks are executed during the parse for exactly this reason: In case they emit HTML the parser has to deal with. 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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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