2014-02-12 43 views
5

Internet Explorer 8(我需要支持,不幸的是,不可協商)顯示the following warning once 5,000,000 "executed script statements" have occurred in one synchronous script execution(例如,來自超時或來自事件處理程序)。對於IE的「停止運行此腳本?」,什麼是「執行腳本語句」?警告櫃檯?

停止運行此腳本?此頁上的腳本導致您的網絡瀏覽器運行緩慢。如果它繼續運行,您的計算機可能會變得無響應。

我想優化一些複雜的重型代碼,以避免此錯誤消息。我已經遵循標準的建議,這是儘可能的使用諸如setTimeout()之類的東西將代碼拆分成單獨的異步塊。如果不創建競爭條件,我不能再做這些事情,所以我期望簡化所有發生多次的代碼,例如在大的for循環內。

要做到這一點,我想知道究竟是什麼IE算作一個「執行的腳本語句」,所以我會知道我在循環中的優化將發揮最大作用而哪些不會。

我查找了「執行的腳本語句」的標準定義,但沒有成功 - 大多數時候使用了「腳本語句」,它似乎是指html <script>標記的內容,這顯然是不同的術語。定義Statement (computer science)很有幫助,但它們如何計算的含義不明確(請參閱下面的示例)。

Here's what Microsoft have to say on the matter(爲便於閱讀,我已經添加了一段時間):

如Internet Explorer 4.0及更高版本,超時不再是基於Windows消息的固定值。 Internet Explorer現在會跟蹤執行的腳本語句的總數,並在每次使用腳本引擎爲當前頁面啓動新腳本執行(例如從超時或事件處理程序)時重置該值。

當該值超過閾值時,Internet Explorer將顯示一個「長時間運行的腳本」對話框。

Internet Explorer不檢查每條指令是否超出限制。腳本引擎定期對所執行的語句數進行輪詢,然後Internet Explorer檢查是否超出限制。由於這種機制,如果在腳本引擎輪詢Internet Explorer之前完成整個腳本的執行,則可以在沒有對話框的情況下執行超過默認限制。

舉,似乎模棱兩可給我一些簡單的例子:

  1. var a = 1, b = 2, c = 3;算一個「執行的腳本語句」和var a = 1; var b = 2; var c = 3;數三?或者都是三個?
  2. if(someFunction()){}(不包括內someFunction()語句是一個語句,或兩個(一個電話加一個條件)?
  3. if(a){}else{}一個條件語句或兩個?如果有,會if(a){}else if(b){}是兩個?
  4. if(a==b||(c&&a==c&&c==d)){}一個,兩個,三個,四個,五個陳述(或更多?)?我知道,像if(a){}這樣的任何東西都會調用一個Javascript函數來轉換爲布爾值 - 這是否會在比較本身上添加其他語句?
  5. var value = someFunction(); if(value){}三個,因爲它增加了一個賦值,或者將函數調用作爲賦值語句的一部分嗎?
  6. 鏈接怎麼樣?例如,如果使用jQuery,那麼(不包括執行的腳本語句內的每個函數)是行$(selector).show().css(obj).appendTo($el);一個「已執行的腳本語句」,還是四個?我想可能會是四個「呼叫」聲明。
  7. 據推測,var $someEl = $(selector).show().css(obj).appendTo($el);會將此增加到五個語句 - 四個呼叫加分配? (IE將不只是指望它作爲一個賦值語句被感動嗎?)

當然以上這些簡單的例子是小混混 - 我試圖「瞭解敵人」這裏可以判斷如何最好優化複雜的循環。

我正在尋找無論是經驗法則或一些解釋例子像上面

+0

我不能說明確的,但'var whatever'幾乎肯定不會計數,因爲該語句不在運行時運行。除此之外,它的_probably_一行代碼執行,如果if(foo){'或您的長jQuery鏈在最後。然而,jQuery鏈可能會在jQuery庫中運行幾百行代碼。換句話說,#1是0,#5是2(用分號隔開),其他所有的都是1.但是你必須遵循代碼路徑來查看在#2,#5中實際運行了多少代碼, #6,#7 –

回答

0

據我瞭解瀏覽器中執行代碼掀起了隊列。

當某些代碼正在運行並且您創建了setTimeout()時,即使您將超時設置爲4毫秒(每個瀏覽器可能不同,下面不做評論),該代碼也不會與其他JavaScript代碼並行執行瀏覽器。相反,函數被放入隊列中。

當前正在執行的腳本完成後,它會在隊列中查找下一個要執行的項目。隊列中可能有事件處理程序(來自用戶輸入,但我認爲它們可能是優先級,不確定)以及諸如Ajax調用響應(如jQuery ajax調用成功代碼等)的事件,它們都被添加到隊列中並且它們被執行一個一次。

JavaScript總是在單線程中運行,並沒有兩個線程並行運行JavaScript代碼。一個線程從隊列中選取一些內容並一次執行一個內容。

注意:你最好不要在big for循環中運行,因爲這會觸發你所得到的錯誤。

+0

setTimeout of 0 has mixed results。它曾經在一些瀏覽器中立即運行,但我不記得我的頭頂哪個。因此,1的超時更安全(在大多數瀏覽器中的行爲完全相同) –

+0

@zyklus我認爲所有瀏覽器現在默認setTimeout(func,0)設置爲setTimeout(func,4)甚至更大(即,有他們會支持的最小下限),但你可能是對的,我可以明白爲什麼這樣做是明智的(特別是我們實際上並不知道每個瀏覽器如何處理這個問題)。 – jwwishart

+0

大多數瀏覽器都這麼做,但正如我所說的,一些瀏覽器用'func()'讀'setTimeout(func,0)'。而且他們並沒有完全「將其改變」爲「4ms」,「10ms」,無論定時器如何,這就是那些瀏覽器的沖刷週期。如果你有一個10ms刷新的瀏覽器,並在週期開始時運行1ms的setTimeout,它將在10ms後運行。但是,如果您先咀嚼9ms的CPU時間,則會在1ms後運行。 –

2

你所要求的只能被猜測,除非一些微軟的IE8開發者來了,並回答你的問題。
作爲一個弱小的青蛙與微軟沒有任何聯繫,我設計了一個簡單的測試,試圖測量語句怎麼算的:

<body> 
<div id='div'></div> 
<script> 
var count = 5000000; 
var res = 0; 
var d = document.getElementById ('div'); 
function fun (aaa) // 1 statement 
{ 
    aaa+= Math.random(); // 1 statement 
    aaa+= Math.random(); // 1 statement 
    aaa+= Math.random(); // 1 statement 
} 
function format (count) // 1 statement 
{ 
    return Math.round(count*100/i)/100; // 1 statement 
} 
function format2 (count) // 1 statement 
{ 
    var a = count*100; //4 statements 
    var b = a/i; 
    var c = Math.round (b); 
    var d = c/100; 
    return d; // 1 statement 
} 

for (var i = 0 ; i != count ; i++) // 2 statements 
{ 
    res += Math.random();      // 1 statement 
    d.innerHTML = format2(count);    // 1 statement 
    d.innerHTML = Math.round(count*100/i)/100; // 1 statement 
    fun (res);         // 1 statement 
} 
</script> 
</body> 

我在XP在VirtualBox的運行在IE8這個腳本。

頁面中顯示的數字大致表示每個循環的語句數(按IE計數)。不精確性可能是由於對語句計數的異步輪詢所致,正如微軟論文中所解釋的那樣。

您可以修改代碼以查看自己將哪種指令計爲語句。

我的經驗觀察至今:

這似乎是一個聲明的確是接近語法定義,即發現,直到下一個;什麼。

  • 環算作2個語句(測試和指數之更新,可能)
  • 函數調用計數爲2條語句,而不管結果受到影響到可變
  • 任意複雜的表達式求值作爲單個語句計數
  • 內建函數不計算爲語句,但每個語句都在用戶定義的語句中執行。

看來你可以通過將計算包裝到更復雜的單個語句中來在5M允許的語句內塞入更多的功率。如果你問我,那麼使用瀏覽器執行重型計算的設計是根本上有缺陷的。