2009-12-18 11 views
25

Uso il caricamento dinamico degli script per ridurre la durata del caricamento iniziale della pagina. Per garantire che le funzioni e gli oggetti definiti da uno script siano accessibili, devo assicurarmi che lo script sia stato completamente caricato.È possibile utilizzare trusted.readyState per rilevare la fine del caricamento dinamico degli script?

Ho sviluppato my own Javascript library a tal fine, e quindi ho fatto un bel po 'di ricerche sull'argomento, studiando come è fatto in diverse librerie. Durante una discussione relativa a questo problema, Kyle Simpson, autore di LABjs, ha dichiarato che:

LABjs (e molti altri caricatori) Impostare sia "onload" e "onreadystatechange" su tutti gli elementi di script, sapendo che alcuni browser fuoco uno, e alcuni spareranno l'altra ...

È possibile trovare un esempio di questo in the current version of jQuery as of this writing, v1.3.2:

// Attach handlers for all browsers 
script.onload = script.onreadystatechange = function(){ 
    if (!done && (!this.readyState || 
    this.readyState == "loaded" || this.readyState == "complete")) { 
     done = true; 
     success(); 
     complete(); 

     // Handle memory leak in IE 
     script.onload = script.onreadystatechange = null; 
     head.removeChild(script); 
    } 
}; 

Questo è lo stato dell'arte, ma durante l'analisi di uno strano comportamento in Opera 9.64, sono giunto alla conclusione che, utilizzando questa tecnica, il callback onload è stato licenziato troppo presto.

Pubblicherò le mie scoperte in risposta a questa domanda e vorrei raccogliere ulteriori prove e feedback dalla comunità.

+0

Qualcuno trova il codice corrente nel ramo jQuery 1.x-master? Sembra che abbiano smesso di usare '.onreadystatechange' e' .onload' e li hanno sostituiti con le promesse? [Clicky] (https://github.com/jquery/jquery/blob/1.x-master/src/ajax.js) – Campbeln

risposta

7

In Opera, la proprietà script.readyState non può essere considerata attendibile. Ad esempio, il readyState "caricato" può essere attivato prima dell'esecuzione dello script in Opera 9.64.

Ho eseguito the same test in Opera 9.64 e Opera 10, con risultati diversi.

In Opera 9.64, il gestore onreadystatechange viene generato due volte, una volta prima e una volta dopo l'esecuzione dello script. La proprietà readyState è "caricato" in entrambi i casi, il che significa che questo valore non può essere attendibile per rilevare la fine dello script di carico:

# Fri Dec 18 2009 17:54:43 GMT+0100 
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
readystatechange: loaded 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 

In Opera 10, il gestore onreadystatechange viene comunque licenziato due volte con il valore " caricati", ma entrambe le volte dopo che lo script corse:

# Fri Dec 18 2009 18:09:58 GMT+0100 
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 
readystatechange: loaded 

Questi differenti comportamenti indicano che non onreadystatechange è un modo affidabile per rilevare la fine di un carico di script in Opera. Poiché Opera supporta anche il listener di onload, è necessario utilizzare questo altro meccanismo.

In base ai risultati di questi test, onreadystatechange deve essere utilizzato solo per rilevare la fine del caricamento degli script in Internet Explorer e non deve essere impostato in altri browser.

+0

Come minimo, puoi ignorare il primo evento. –

+2

@Justin Johnson che sembra imbarazzante, conterai gli eventi "caricati", ma solo in Opera? –

3

In Firefox, Safari e Chrome, viene chiamato il gestore di onreadystatechange.

ho creato un breve test case, creando uno script dinamico con solo il set gestore onreadystatechange:

<script type="text/javascript" language="javascript"> 
bezen.log.info(new Date(),true); 
bezen.log.info(navigator.userAgent,true); 

// Activate logs 
bezen.log.on(); 
bezen.log.info('Test for script.readyState behavior started'); 

var script = document.createElement('script'); 
script.src = 'test1.js'; 
script.onreadystatechange = function(){ 
    bezen.log.info('readystatechange: '+script.readyState); 
}; 
document.body.appendChild(script); 
bezen.log.info('Added script with onreadystatechange handler'); 
</script> 

ho eseguito il test su un file locale in Firefox 2, Firefox 3, Firefox 3.5, Safari 3, Safari 4 e Chrome 3, ed ha ottenuto risultati simili (qui i dati registrati in FF 3.5):

Fri Dec 18 2009 17:53:58 GMT+0100 
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 

L'onreadystatechange non viene mai chiamato. In questi browser, solo il listener di onload è utile per rilevare la fine del caricamento di uno script, non è necessario il onreadystatechange.

1

In Internet Explorer, il gestore onreadystatechange si attiva come previsto, dopo la fine dello script.

ho eseguito la same test in Internet Explorer 6, Internet Explorer 7 e Internet Explorer 8, con risultati simili in questi tre browser (qui i dati registrati in Internet Explorer 6):

Fri Dec 18 18:14:51 UTC+0100 2009 
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: complete 

Qui, con un prova usando un file locale, il readyState è sempre "completo", ed era sempre lo stesso dopo diversi aggiornamenti di pagina.

Tuttavia, come indicato in this post by Nicholas C. Zakas, è possibile anche osservare "caricato" e "completo", o semplicemente "caricato", in circostanze diverse.

1

Ho trovato che internet explorer (test in 9) NON SEMPRE ha lo script pronto quando readyState === 'caricato'. Ho avuto successo usando questo gestore di eventi (in 9 ovviamente) onactivate. Mi stavo strappando i capelli prima.

0

Risultati simili in Chrome.

non prende onReady ...

Basta onload e OnError.