2010-05-10 11 views
6

Aggiungo dinamicamente alcuni tag <script> all'elemento head dopo il caricamento della pagina. Capisco che gli script siano caricati in modo asincrono, ma posso aspettarmi che vengano analizzati nell'ordine in cui vengono aggiunti?L'aggiunta dinamica di script deve essere ordinata?

Vedo il comportamento previsto in Firefox, ma non in Safari o Chrome. Guardando il documento in strumenti di sviluppo Chrome e Firebug, entrambi mostrano le seguenti -

<html> 
    <head> 
    ... 
    <script type="text/javascript" src="A.js"></script> 
    <script type="text/javascript" src="B.js"></script> 
    </head> 
    ... 
</html> 

Tuttavia guardando la vista delle risorse di caricamento, Chrome sembra di analizzare a seconda di quale viene restituito prima dal server, mentre Firebug li carica sempre in ordina che i tag dello script siano stati aggiunti, anche quando B viene restituito prima dal server.

Devo aspettarmi che Chrome/Safari analizzi i file nell'ordine specificato? Utilizzando Chrome 5.0.375.29 beta su OS X 10.6.3

EDIT (10/5/10): Quando dico parse, intendo eseguire - può vedere molti benefici di parsing aggressiva - thx rikh

EDIT (11/5/10): Ok, quindi ho messo insieme un test sulla falsariga di quello di juandopazo qui sotto. Tuttavia ho aggiunto una combinazione di cose, tra cui

  1. Aggiunta dell'elemento di script alla testa direttamente con javascript. (Test A -> D)
  2. Aggiunta dell'elemento di script alla testa usando il metodo append() di jquery. (Test E -> H)
  3. 'Caricamento' lo script con il metodo getScript() di jquery. (Test I -> L)

Ho anche provato tutte le combinazioni degli attributi 'asincrono' e 'rinvia' sui tag dello script.

È possibile accedere al test qui - http://dyn-script-load.appspot.com/ e visualizzare l'origine per vedere come funziona. Gli script caricati chiamano semplicemente la funzione update().

La prima cosa da notare è che solo il primo e il terzo metodo sopra funzionano in parallelo - il secondo esegue le richieste in sequenza. Si può vedere un grafico di questa qui -

Immagine 1 - Grafico di Richiesta Lifecycle
Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png

E 'anche interessante il fatto che l'append jQuery() approccio anche blocchi getScript() chiama - si può vedere che nessuno di li eseguono fino a quando tutte le chiamate append() non sono complete e quindi vengono eseguite tutte in parallelo. La nota finale su questo è che il metodo jQuery append() rimuove apparentemente i tag di script dalla testa del documento dopo che sono stati eseguiti. Solo il primo metodo lascia i tag di script nel documento.

Chrome Risultati

I risultati sono che Chrome esegue sempre il primo script di restituire, a prescindere dalla prova. Questo significa che tutti i test 'falliscono', tranne il metodo jQuery append().

Immagine 2 - Chrome 5.0.375.29 beta Risultati
Chrome Results http://dyn-script-load.appspot.com/images/chromeDynScript.png

Firefox Risultati

su Firefox, tuttavia, sembra che se si usa il primo metodo, e async è falso (cioè non impostato), quindi gli script in modo affidabile l'esecuzione in ordine.

Immagine 3 - FF 3.6.3 Risultati
FF Results http://dyn-script-load.appspot.com/images/ffDynScript.png

Nota che Safari sembra dare risultati diversi nella stessa maniera come Chrome, che ha un senso.

Inoltre, ho solo un ritardo di 500 ms sullo script lento, solo per mantenere il tempo di inizio-> fine. Potrebbe essere necessario aggiornare un paio di volte per vedere che Chrome e Safari falliscono su tutto.

Mi sembra che senza un metodo per fare questo, non stiamo sfruttando la possibilità di recuperare i dati in parallelo, e non vi è alcun motivo per cui non dovremmo (come mostra Firefox).

+0

che ho sollevato questo come un bug nei problemi cromati Registrazione - http://code.google.com/p/chromium/issues/detail? id = 46109 – hawkett

risposta

2

Siamo spiacenti di rispondere alla mia domanda, ma è passato un po 'di tempo e abbiamo trovato una soluzione. Ciò che abbiamo creato è stato caricare contemporaneamente javascript come testo contenuto in un oggetto json, quindi utilizzare eval() una volta caricati per eseguirli nell'ordine corretto. Carico simultaneo più esecuzione ordinata. A seconda del tuo caso d'uso potresti non aver bisogno di JSON. Approssimativamente, ecco alcune codice che mostra quello che abbiamo fatto -

// 'requests' is an array of url's to javascript resources 
var loadCounter = requests.length; 
var results = {}; 

for(var i = 0; i < requests.length; i++) { 
    $.getJSON(requests[i], function(result) { 
     results[result.id] = result; 
     ... 
     if(--loadCounter == 0) finish(); 
    }); 
} 

function finish() { 
    // This is not ordered - modify the algorithm to reflect the order you want 
    for(var resultId in results) eval(results[resultId].jsString); 
} 
0

A quanto ho capito, sono pensati per essere eseguiti nell'ordine in cui appaiono nel documento. Alcuni browser potrebbero essere in grado di eseguire un parsing fuori servizio, ma dovrebbero comunque essere eseguiti nell'ordine corretto.

+0

Questa era la mia comprensione. – hawkett

0

No, non ci si può aspettare che tutti i browser rinviino l'esecuzione di entrambi gli script fino a quando non vengono caricati entrambi (** specialmente quando li si aggiunge dinamicamente).

Se si desidera eseguire codice in B.js solo dopo A.js si carica allora la cosa migliore è quella di aggiungere un onload callback per A.js che imposta una variabile e un altro per B.js che controlla per vedere se è stata impostata questa variabile, allora esegue la funzione necessaria in B.js se ha (e se A.js non è caricato, avvia un timer che controlla periodicamente finché non è stato caricato).

0

L'ordine di download e l'ordine di esecuzione non sono la stessa cosa. Nella tua pagina, anche se B.js viene scaricato per primo, il motore del browser aspetterà che A.js continui ad elaborare la pagina.

Gli script vengono elaborati definitivamente, non solo nell'ordine in cui sono stati visualizzati nel documento, ma anche nel luogo in cui sono stati visualizzati.

Immagina se non sarebbe così, ci sarebbero molti errori se il tuo piccolo script che usa jQuery viene scaricato ed elaborato prima della libreria jQuery.

Inoltre, quando si esegue un "document.write" in un file js, appare dove è stato dichiarato lo script. Non è possibile accedere agli oggetti DOM che appaiono dopo la dichiarazione di script nessuno dei due.

Questo è il motivo per cui ci sono consigli per inserire script nella parte inferiore della pagina, per impedire la loro esecuzione troppo presto e ridurre il "tempo di caricamento percepito" della pagina, perché il motore di rendering del browser viene interrotto non appena lo script viene elaborato.

Mike

EDIT: se vengono aggiunti dinamicamente con javascript, penso che siano elaborati nell'ordine in cui sono stati aggiunti nel tempo.

+0

Grande questo è quello che mi aspettavo, quindi se vedo gli script * not * eseguiti nell'ordine in cui appaiono nel documento (che è anche l'ordine in cui sono stati aggiunti in tempo), allora questo sarebbe un bug in WebKit? Ho quattro cose che mi dicono cosa sta succedendo (1) La struttura effettiva del DOM che mostra gli script nel giusto ordine (2) La vista del carico di risorse negli strumenti di sviluppo che mostrano il secondo script ricevuto per primo (3) Il log della console mostra l'ordine in cui gli script vengono aggiunti (in tempo) e (4) il log della console che mostra il secondo script in esecuzione per primo – hawkett

+0

Forse nell'ultima riga di A.js, inserisci una riga per includere B.js tramite un "document.write"? –

+0

L'obiettivo principale è caricare gli script in parallelo, ma eseguirli nell'ordine in cui sono stati aggiunti. Funziona in Firefox, ma non in chrome/safari. Posso utilizzare il 2 ° approccio nel test (vedi modifica nel post principale) per garantire il corretto ordine di esecuzione in tutti i browser, ma non è simultaneo. Sto pensando che piuttosto che prendere l'approccio suggerito per ottenere il caricamento seriale (e quindi l'esecuzione), vorrei andare con jQuery.append(), in quanto non è necessario alcun codice aggiuntivo negli script stessi. Detto questo, ho il carico seriale che funziona proprio ora - sto cercando una soluzione di carico simultaneo per migliorare le prestazioni - evviva. – hawkett

0

Si potrebbe caricare b.js da a.js essere sicuri al 100% ... anche se mi piacerebbe la risposta definitiva a questa domanda me stesso, soprattutto con carico di sincronizzazione ajax di script.

+0

Funziona sicuramente - Sono in procinto di allontanarmi dal fare ciò, per ottenere i benefici delle prestazioni del caricamento simultaneo degli script :) – hawkett

0

Stavo indagando su questo mentre lavoravo su una piccola libreria che carica i moduli dinamicamente come YUI 3. Ho creato qui un piccolo test che carica due script che inseriscono semplicemente il contenuto in div. Uno è un file JS comune e l'altro è un file PHP che attende 3 secondi per l'esecuzione.

http://www.juandopazo.com.ar/tests/asyn-script-test.html

Come si può vedere, gli script vengono eseguiti quando hanno finito il caricamento, e non nell'ordine in cui li si aggiunge al DOM, in tutti i browser.

+0

Ho dato un'occhiata alla struttura DOM per il test, e ho notato un paio di cose - in primo luogo gli script sono nel corpo piuttosto che nella testa, e il secondo script è elencato per primo - quindi se l'ordine fosse onorato, ci si aspetterebbe che lo script 2 fosse eseguito per primo - un buon test sarebbe bello vedere i risultati quando i tag dello script sono In ordine. ta – hawkett

+0

Giusto. Scusa, ho dimenticato di metterli in testa. Erano nell'ordine sbagliato perché ho usato insertBefore() invece di appendChild(). L'ho cambiato e il risultato è lo stesso. Si dovrebbe guardare alla scrittura di una sorta di coda. Chiedi moduli in diversi file che chiamano metodi da un oggetto globale. Dai un'occhiata a come funziona YUI3. Gli script con il codice di solito appare come:. YUI() utilizzare ('module1', 'module2', la funzione (Y) {// fare qualcosa }); E ogni modulo inizia: YUI().add ('module1', function (Y) { // aggiungi i tuoi contenuti a Y }); – juandopazo

+0

Grazie per questo - non ho abbastanza reputazione per scusarmi. Sto solo cercando di capire perché vedo firefox comportarsi come previsto nel mio scenario, ma non nel tuo. Sembra che abbia probabilmente frainteso la mia situazione. – hawkett

Problemi correlati