簡體   English   中英

Javascript尾遞歸

[英]Javascript tail recursion

為什么以下代碼如此運行.....慢....?

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

有兩個原因:

  1. 在函數對象上使用caller屬性會帶來開銷(並且是非標准的)

  2. 使用arguments偽數組的方式相同(IIRC,這將使函數調用的速度降低2-5倍,具體取決於您使用的瀏覽器)

  3. setTimeout通常將花費不少於 10ms的時間來回調您的函數(盡管Chrome有時會更快一些),即使您將超時指定為0。 這可能是最大的原因:〜10ms處的5,000次迭代為50秒。

最后一項是我說的原因:

如果您有很多循環迭代(例如,幾百個而不是15個),那么在每次迭代中進行一小部分而不是在每次迭代時都屈服可能是值得的。 產量需要一個可測量的時間(通常〜10-15ms)。

...在我對您最近的其他問題的回答中

請注意,您可以在不使用callerarguments情況下重寫代碼,從而使代碼更加清晰:

var i = 0;

f();

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

另外:我注意到您在代碼示例中使用了document.write 如果使用頁面解析期間執行的代碼(這是可以使用document.write的唯一位置)來執行此操作,而不是使用解析頁面后使用事件處理程序觸發的代碼,則不能使用setTimeout 這是因為通過代碼OUPUTS document.write 必須與頁面加載HTML解析器同步運行。 正是由於以下原因,腳本塊在解析期間執行:如果它們發出HTML,則解析器必須處理。 如果要解析修改頁面(我建議這樣做),則要使用DOM方法來獲取元素引用,然后使用DOM方法來添加該頁面,或者(這既容易又快速地運行)在元素上設置innerHTML屬性。

從這兩個問題中我的感覺是,您可能確實希望研究Web worker ,並且僅對不支持它們的瀏覽器使用以上內容(我擔心IE9,但我敢打賭IE9會擁有它們-其他所有主要的對象現在都有)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM