2009-11-02 20 views
11

Sono compresi alcuni contenuti correlati su misc. pagine web aggiungendo un tag <script> vicino alla fine del tag <body>, che carica quindi altri file javascript. Il flusso è un po 'contorto, quindi cercherò di spiegarlo prima di porre la mia domanda:Arrestare IE dal caricamento dello script incluso dinamicamente due volte

  • Un browser carica una pagina con il nostro elemento <script> vicino alla fine del <body> elemento
  • L'attributo src del script di punti tag a un file javascript che (in alcuni casi) inietta un secondo elemento <script>
  • l'attributo src dei iniettati <script> punti di elemento a un altro file javascript, che inietta infine alcuni contenuti da parte appropriata della pagina.

Stiamo utilizzando questo approccio in due fasi per poter eseguire alcune elaborazioni di base prima di decidere se includere il contenuto finale, che potrebbe richiedere del tempo per il caricamento.

Il problema è che IE8 (e forse versioni precedenti) carica l'ultimo javascript due volte. Sembra che l'atto di impostare l'attributo src inneschi un carico, ma aggiungerà il tag script al DOM. C'è un modo per evitarlo?

Ho creato un problema bare-bones demo. Se hai qualche modo di tracciare le richieste HTTP, vedrai che IE8 carica js_test2.js due volte.

risposta

15

La differenza principale è che IE esegue un elemento di script per la prima volta che viene aggiunto al childNodes di un elemento padre, indipendentemente dal fatto che l'elemento padre sia effettivamente nel documento. Gli altri browser eseguono solo lo script quando viene aggiunto a un nodo all'interno dell'albero del documento di childNodes.

di domManip funzione (linea 524 di jQuery 1.3.2), che è chiamato da append e altri metodi di jQuery simili, cerca di essere intelligente e chiede evalScript per eventuali <script> elementi che trova nella finale analizzata HTML, per eseguire l'jQuery script (eseguendo richieste AJAX se necessario per script esterni). (Gli effettivi elementi di script sono stati rimossi dai childNode analizzati per impedirne l'esecuzione al momento dell'inserimento nel documento, presumibilmente in modo che gli script vengano eseguiti una sola volta quando il contenuto che li contiene viene aggiunto in più elementi contemporaneamente.)

Tuttavia, poiché la precedente funzione clean, durante l'analisi dell'HTML, ha aggiunto l'elemento di script a un div wrapper, IE avrà già eseguito lo script. Quindi ottieni due esecuzioni.

La cosa migliore da fare è evitare di utilizzare le funzioni domManip come append con stringhe HTML quando si sta facendo qualcosa con gli script.

Infatti, dimentica di inserire il contenuto in una stringa HTML serializzata e ottenere jQuery per analizzarlo; basta farlo il molto più affidabile pianura DOM modo:

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

(Per essere onesti, dopo aver visto il codice sorgente stomaco-ribollimento della funzione clean, sto avendo seri dubbi su come usare jQuery HTML-corda a base di- . manipolazioni DOM per qualsiasi cosa si suppone per sistemare i bug del browser, ma l'elaborazione muto-regex mi sembra probabile che a causare tanti problemi quanti ne risolva)

inciso con questa chiamata iniziale:.

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

Non hai bisogno di unes mantello qui; Non so perché così tante persone lo facciano. La sequenza </ deve essere evitata in uno script inline poiché termina il tag <script> e se si sta eseguendo XHTML < e & dovrebbe essere evitato anche (o ]]> se si utilizza un wrapper CDATA), ma c'è un modo più semplice modo di fare tutto ciò che con appena JavaScript stringhe letterali:

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

Grazie per questa risposta molto approfondita. Sono davvero tornato al modo DOM più tradizionale, e ora funziona bene. Per quanto riguarda il non escape nella chiamata iniziale: se ricordo bene ho copiato il codice che Google Analytics utilizza per includere il loro script, sotto l'ipotesi (forse falsa) che se qualcuno sa come includere in modo sicuro un javascript remoto, è il popolo GA . Grazie per il chiarimento. – stiang

2

Sembrerebbe che jquery stia recuperando la seconda istanza di js_test2 utilizzando XmlHttpRequest.

Perché non lo so ma è il comportamento di JQuery che è necessario indagare.

+0

Questo è solo strano, ma sembra hai ragione. Se uso appendChild invece dell'appendice di jQuery, non carica js_test2.js due volte. Immagino che se avessi realizzato la demo/veramente/bare-bones (senza jQuery), l'avrei scoperto io stesso. Grazie! – stiang

+0

Ho fatto delle indagini. I risultati (sotto) non sono belli. – bobince

4

Ho visto che il comportamento si verificava su altre versioni di IE in circostanze simili (come la clonazione dei nodi <script>) e non ho mai saputo come interrompere l'esecuzione dello script due volte, quindi quello che ho finito è stato aggiungere una guardia sul codice dello script per non funzionare due volte. E 'stato qualcosa di simile:

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

Se non riuscite a trovare un modo di prevenire lo script per eseguire due volte, si consiglia di provare questo approccio, invece.

+0

impressionante, stava cercando di trovare un modo per controllare se una variabile globale è stata definita, senza ovviamente definirla falsa prima dell'esecuzione dello script. Grazie! –

1

È possibile controllare per vedere se uno script è già nel documento prima di caricare 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

E 'possibile che questo è perché si utilizza document.write quando sei già in un elemento <script>. Hai provato ad aggiungere <head> anziché document.write?

1

Trovo lo stesso problema, si verifica solo in IE.

html() catene metodo di jQuery è: html>append>domManip>clean

clean() metodo utilizzare innerHTML make stringa DOM, innerHTML in IE ha un bug che script tag verrà caricato immediatamente (primo carico), jQuery evalScript tag di script alla fine del metodo domManip (caricamento ajax) .questo file di script viene caricato due volte in IE.

penso jQuery dovrebbe risolvere il problema, aggiornare il metodo clean()

Problemi correlati