2009-11-02 75 views
11

我在misc中加入了一些相關內容。在<body>標記末尾附近添加一個<script>標記,然後加載其他JavaScript文件。流量是有點令人費解,所以我會試着問我的問題前解釋它:停止IE加載動態包含腳本兩次

  • 瀏覽器加載一個頁面,我們<script>元件附近的<body>元素
  • 的src屬性的結束腳本標記指向一個JavaScript文件(在某些情況下)注入第二個<script>元素
  • 注入的<script>元素的src屬性指向另一個JavaScript文件,該文件最終將一些內容注入頁面的相應部分。

我們使用這種兩階段方法能夠在決定是否包含最終內容之前進行一些基本處理,這可能需要一些時間才能加載。

問題是,IE8(也許是舊版本)加載最後一次javascript兩次。看起來,設置src屬性的行爲會觸發加載,但是也會將腳本標記附加到DOM。有什麼辦法可以避免這種情況?

我已經創建了一個bare-bones demo的問題。如果你有一些跟蹤HTTP請求的方法,你會看到IE8加載js_test2.js兩次。

回答

15

根本的區別是,IE執行腳本元素在第一時間將其添加到父元素節點的childNodes,不管父元素是否實際在文檔中。其他瀏覽器僅在將腳本添加到文檔的childNodes樹中的節點時才執行腳本。

jQuery的domManip函數(線的jQuery 1.3.2的524),這是由append和其它類似jQuery方法調用,試圖要巧和用於它發現在最終的已解析的HTML任何<script>元素調用evalScript,以執行腳本(通過爲外部腳本執行AJAX請求)。 (實際的腳本元素已經從解析的childNodes中移除,以阻止它們在插入到文檔中時被執行,大概是這樣,當包含它們的內容被一次性地添加到多個元素中時,腳本纔會被執行一次。)

但是,因爲前面的clean函數在解析HTML時將腳本元素附加到包裝div,因此IE將已經執行腳本。所以你會得到兩次處決。

要做的最好的事情是避免使用domManip函數,如append與HTML字符串,當你做任何與腳本。實際上,忘記把你的內容放入一個序列化的HTML字符串中,然後讓jQuery來解析它;只是做了更可靠平原DOM方法:

var s= document.createElement('script'); 
s.type= 'text/javascript'; 
s.charset= 'UTF-8'; 
s.src= 'js_test2.js'; 
document.getElementById('some_container').appendChild(s); 

(說實話,觀看clean功能的讓人噁心的源代碼後,我在有關使用jQuery的嚴重懷疑HTML串基。DOM操作的任何東西它應該修復了瀏覽器的bug,但愚蠢的正則表達式處理在我看來,可能因爲它解決了導致許多問題)

這個初始呼叫

順便說一句:

document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E")); 

你不需要聯合國這裏披肩;我不知道爲什麼這麼多人這樣做。內聯腳本中需要避免使用</,因爲它會結束<script>標記,並且如果您正在執行XHTML <&也應該避免(如果您使用的是CDATA包裝器,則爲]]>),但是更容易盡一切只用JavaScript字符串字面量的方式:

document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>")); 
+0

謝謝你這個非常透徹的答案。我確實已經回到了更傳統的DOM方式,現在它運行良好。 關於最初調用中的無法使用的問題:如果我沒有記錯的話,我複製了Google Analytics用來包含腳本的代碼,根據(也許是錯誤的)假設,如果有人知道如何強健地包含遠程JavaScript,那麼GA人。感謝您的澄清。 – stiang

2

似乎jquery使用XmlHttpRequest獲取js_test2的第二個實例。

爲什麼我不知道,但它的JQuery的行爲,你需要調查。

+0

這只是奇怪的,但看起來你是對的。如果我使用appendChild而不是jQuery的append,它不會加載js_test2.js兩次。我猜如果我已經制作了演示/真的/沒有jQuery(沒有jQuery),我會自己發現它。謝謝! – stiang

+0

我已經做了一些調查。結果(下)不好。 – bobince

4

我見過類似情況下(例如克隆<script>節點)在其他版本IE上發生的行爲,我從來不知道如何停止腳本執行兩次,所以我最終做的是添加腳本代碼的後衛不會運行兩次。它是這樣的:

if (typeof(loaded) == 'undefined') { 
    // the whole code goes in here 
    var loaded = true; 
} 

如果您找不到防止腳本執行兩次的方法,您可能需要嘗試使用該方法。

+0

真棒,試圖找到一種方法來檢查是否定義了一個全局變量,當然在腳本運行之前沒有將其定義爲false。謝謝! –

1

您可以檢查,看是否有劇本已經在文件中加載之前IT-

function fetchscript(url, callback){ 
var S= document.getElementsByTagName('script'), L= S.length; 
while(L){ 
    if(S[--L].src== url) return true; 
} 
//create and append script and any callbacks 
} 
0

這是可能的,這是因爲你用document.write當你在一個<script>元素是已。你有沒有嘗試追加到<head>而不是document.write

1

我發現同樣的問題,只發生在IE中。

jQuery的html()方法鏈是:html>append>domManip>clean

clean()方法使用innerHTML化妝字符串DOM,innerHTML在IE中有script標籤將立即加載一個bug(第一負載),jQuery的evalScript腳本標記在年底domManip方法(ajax加載)。然後腳本文件在IE中加載兩次。

我認爲jQuery應該解決這個問題,更新clean()方法