Sequenza di caricamento ed esecuzione di una pagina Web?


244

Ho realizzato alcuni progetti basati sul Web, ma non penso troppo al caricamento e alla sequenza di esecuzione di una normale pagina Web. Ma ora ho bisogno di conoscere i dettagli. È difficile trovare risposte da Google o SO, quindi ho creato questa domanda.

Una pagina di esempio è così:

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

Quindi, ecco le mie domande:

  1. Come si carica questa pagina?
  2. Qual è la sequenza del caricamento?
  3. Quando viene eseguito il codice JS? (in linea ed esterno)
  4. Quando viene eseguito (applicato) il CSS?
  5. Quando viene eseguito $ (document).
  6. Abc.jpg verrà scaricato? O scarica semplicemente kkk.png?

Ho la seguente comprensione:

  1. Il browser carica inizialmente l'html (DOM).
  2. Il browser inizia a caricare le risorse esterne dall'alto verso il basso, riga per riga.
  3. Se <script>viene soddisfatto, il caricamento verrà bloccato e attenderà il caricamento e l'esecuzione del file JS, quindi continuerà.
  4. Altre risorse (CSS / immagini) vengono caricate in parallelo ed eseguite se necessario (come i CSS).

O è così:

Il browser analizza l'html (DOM) e ottiene le risorse esterne in una struttura simile a uno stack o ad array. Dopo aver caricato l'html, il browser inizia a caricare le risorse esterne nella struttura in parallelo ed esegue, fino a quando non vengono caricate tutte le risorse. Quindi il DOM verrà modificato in base ai comportamenti dell'utente in base al JS.

Qualcuno può dare una spiegazione dettagliata di ciò che accade quando hai la risposta di una pagina HTML? Questo varia in diversi browser? Qualche riferimento a questa domanda?

Grazie.

MODIFICARE:

Ho fatto un esperimento su Firefox con Firebug. E mostra come la seguente immagine: testo alternativo


11
Steve Souders ha lavorato molto in questo campo. Google per steve + souders + high + performance e dai un'occhiata.
anddoutoi,

3
Non intendo il tuning delle prestazioni. Voglio conoscere i dettagli.
Zhu Tao,

2
Leggendo il suo lavoro la mia comprensione di come "funziona" in dettaglio è aumentata di dieci volte, quindi è ancora un commento valido. Non sono autorizzato dal copyright a citare il suo intero libro qui, quindi suggerisco ancora di cercare il suo lavoro.
anddoutoi,

3
Una grande descrizione dell'ordine in cui accadono le cose è qui
Gerrat,

Risposte:


277

Secondo il tuo campione,

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

all'incirca il flusso di esecuzione è il seguente:

  1. Il documento HTML viene scaricato
  2. Inizia l'analisi del documento HTML
  3. Raggiunge l'analisi HTML <script src="jquery.js" ...
  4. jquery.js viene scaricato e analizzato
  5. Raggiunge l'analisi HTML <script src="abc.js" ...
  6. abc.js viene scaricato, analizzato ed eseguito
  7. Raggiunge l'analisi HTML <link href="abc.css" ...
  8. abc.css viene scaricato e analizzato
  9. Raggiunge l'analisi HTML <style>...</style>
  10. Le regole CSS interne vengono analizzate e definite
  11. Raggiunge l'analisi HTML <script>...</script>
  12. Javascript interno viene analizzato ed eseguito
  13. Raggiunge l'analisi HTML <img src="abc.jpg" ...
  14. abc.jpg viene scaricato e visualizzato
  15. Raggiunge l'analisi HTML <script src="kkk.js" ...
  16. kkk.js viene scaricato, analizzato ed eseguito
  17. L'analisi dei documenti HTML termina

Si noti che il download può essere asincrono e non bloccante a causa dei comportamenti del browser. Ad esempio, in Firefox esiste questa impostazione che limita il numero di richieste simultanee per dominio.

Inoltre, a seconda che il componente sia già stato memorizzato nella cache o meno, il componente potrebbe non essere più richiesto in una richiesta futura. Se il componente è stato memorizzato nella cache, il componente verrà caricato dalla cache anziché dall'URL effettivo.

Al termine dell'analisi e il documento è pronto e caricato, gli eventi onloadvengono generati. Quindi quando onloadviene sparato, $("#img").attr("src","kkk.png");viene eseguito. Così:

  1. Il documento è pronto, il caricamento è attivato.
  2. Hit di esecuzione Javascript $("#img").attr("src", "kkk.png");
  3. kkk.png viene scaricato e caricato in #img

L' $(document).ready()evento è in realtà l'evento generato quando tutti i componenti della pagina sono caricati e pronti. Per saperne di più: http://docs.jquery.com/Tutorials:Introducing_$ (documento) .ready ()

Modifica: questa parte elabora di più sul parallelo o no:

Per impostazione predefinita, e dalla mia attuale comprensione, il browser di solito esegue ogni pagina in 3 modi: parser HTML, Javascript / DOM e CSS.

Il parser HTML è responsabile dell'analisi e dell'interpretazione del linguaggio di markup e quindi deve essere in grado di effettuare chiamate agli altri 2 componenti.

Ad esempio quando il parser si imbatte in questa linea:

<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>

Il parser effettuerà 3 chiamate, due a Javascript e una a CSS. In primo luogo, il parser creerà questo elemento e lo registrerà nello spazio dei nomi DOM, insieme a tutti gli attributi relativi a questo elemento. In secondo luogo, il parser chiamerà per associare l'evento onclick a questo particolare elemento. Infine, effettuerà un'altra chiamata al thread CSS per applicare lo stile CSS a questo particolare elemento.

L'esecuzione è top down e single thread. Javascript può sembrare multi-thread, ma il fatto è che Javascript è single thread. Questo è il motivo per cui quando si carica un file javascript esterno, l'analisi della pagina HTML principale viene sospesa.

Tuttavia, i file CSS possono essere scaricati contemporaneamente perché vengono sempre applicate le regole CSS - il che significa che gli elementi vengono sempre riverniciati con le regole CSS più recenti definite - rendendolo quindi sbloccabile.

Un elemento sarà disponibile nel DOM solo dopo che è stato analizzato. Pertanto, quando si lavora con un elemento specifico, lo script viene sempre inserito dopo o all'interno dell'evento onload della finestra.

Script come questo causeranno errori (su jQuery):

<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>
<div id="mydiv">Hello World</div>

Perché quando lo script viene analizzato, l' #mydivelemento non è ancora definito. Invece questo avrebbe funzionato:

<div id="mydiv">Hello World</div>
<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>

O

<script type="text/javascript">/* <![CDATA[ */
  $(window).ready(function(){
                    alert($("#mydiv").html());
                  });
/* ]]> */</script>
<div id="mydiv">Hello World</div>

4
Grazie. Ma hai detto che il download può essere asincrono e non bloccante a causa dei comportamenti del browser , quindi che tipo di componenti possono essere scaricati in asyn (prendi FF come istanza)? <script>bloccherà altri componenti, giusto? Qualche riferimento sulle specifiche per ciascun browser?
Zhu Tao,

4
$ (documento) .ready () viene generato quando il DOM è completo, non quando vengono caricati tutti i componenti della pagina
Pierre

2
@Pierre per componenti di pagina intendevo il DOM -> qualunque componente nel DOM.
mauris,

3
solo per chiarire ... il normale window.onload avviene dopo il # 17 ... quindi in quale # viene eseguito il codice $ (document) .ready () di jquery? # 12? ma il DOM stesso è caricato al numero 1 giusto?
armyofda12mnkeys

1
Se nella scheda <body>, se aggiungiamo un <link href = "bootstrap.min.css" rel = "foglio di stile" /> tra tag <img> e <script> di img non viene visualizzato fino a quando bootrap non viene scaricato ... quindi penso che il passaggio [13], [14] abbia bisogno di modifiche ... qualcuno può spiegare quel comportamento?
Bhuvan,

34

1) HTML scaricato.

2) HTML viene analizzato progressivamente. Quando viene raggiunta una richiesta per una risorsa, il browser tenterà di scaricare la risorsa. Una configurazione predefinita per la maggior parte dei server HTTP e della maggior parte dei browser è di elaborare solo due richieste in parallelo. IE può essere riconfigurato per scaricare in parallelo un numero illimitato di risorse. Steve Souders è stato in grado di scaricare oltre 100 richieste in parallelo su IE. L'eccezione è che le richieste di script bloccano le richieste di risorse parallele in IE. Questo è il motivo per cui si consiglia vivamente di inserire tutto JavaScript in file JavaScript esterni e di inserire la richiesta appena prima del tag body di chiusura nell'HTML.

3) Una volta analizzato l'HTML, viene eseguito il rendering del DOM. Il CSS è reso in parallelo al rendering del DOM in quasi tutti gli user agent. Di conseguenza si consiglia vivamente di inserire tutto il codice CSS in file CSS esterni richiesti il ​​più in alto possibile nella sezione <head> </head> del documento. Altrimenti la pagina viene renderizzata fino al verificarsi della posizione della richiesta CSS nel DOM e quindi il rendering ricomincia dall'alto.

4) Solo dopo che il DOM è stato completamente renderizzato e le richieste per tutte le risorse nella pagina sono state risolte o il timeout JavaScript viene eseguito dall'evento onload. IE7, e non sono sicuro di IE8, non scade rapidamente le risorse se una richiesta HTTP non riceve una risposta HTTP. Ciò significa che un asset richiesto da JavaScript inline alla pagina, ovvero JavaScript scritto in tag HTML che non è contenuto in una funzione, può impedire l'esecuzione dell'evento onload per ore. Questo problema può essere attivato se tale codice incorporato è presente nella pagina e non viene eseguito a causa di una collisione dello spazio dei nomi che causa un arresto anomalo del codice.

Dei passaggi sopra quello che richiede più CPU è l'analisi del DOM / CSS. Se vuoi che la tua pagina venga elaborata più velocemente, allora scrivi un CSS efficiente eliminando le istruzioni ridondanti e consolidando le istruzioni CSS nel minor numero possibile di riferimenti agli elementi. Ridurre il numero di nodi nella struttura del DOM produrrà anche un rendering più veloce.

Tieni presente che ogni risorsa richiesta dal tuo HTML o persino dalle risorse CSS / JavaScript è richiesta con un'intestazione HTTP separata. Ciò consuma larghezza di banda e richiede l'elaborazione per richiesta. Se vuoi caricare la tua pagina il più velocemente possibile, riduci il numero di richieste HTTP e riduci le dimensioni del tuo HTML. Non stai facendo alcun favore alla tua esperienza utente facendo una media del peso della pagina a 180k dal solo HTML. Molti sviluppatori sottoscrivono un errore che un utente prende in considerazione la qualità del contenuto della pagina in 6 nanosecondi e quindi elimina la query DNS dal suo server e brucia il suo computer se non è soddisfatto, quindi forniscono la pagina più bella possibile su 250k di HTML. Mantieni il tuo HTML breve e dolce in modo che un utente possa caricare le tue pagine più velocemente.


2
consolidare le istruzioni CSS nel minor numero possibile di riferimenti di elementi Sembra strano. Se devo modellare tre elementi, devo fare riferimento esattamente a tre elementi. Non posso fare riferimento a uno di stile dieci, vero? O elaborate su questo
Green

12

Apri la tua pagina in Firefox e ottieni il componente aggiuntivo HTTPFox. Ti dirà tutto ciò di cui hai bisogno.

Ho trovato questo su archivist.incuito:

http://archivist.incutio.com/viewlist/css-discuss/76444

Quando si richiede per la prima volta una pagina, il browser invia una richiesta GET al server, che restituisce l'HTML al browser. Il browser inizia quindi ad analizzare la pagina (possibilmente prima che tutto sia stato restituito).

Quando trova un riferimento a un'entità esterna come un file CSS, un file di immagine, un file di script, un file Flash o qualsiasi altra cosa esterna alla pagina (sullo stesso server / dominio o meno), si prepara a fare un'ulteriore richiesta GET per quella risorsa.

Tuttavia, lo standard HTTP specifica che il browser non deve effettuare più di due richieste simultanee allo stesso dominio. Quindi inserisce ciascuna richiesta in un determinato dominio in una coda e, quando viene restituita ogni entità, avvia la successiva nella coda per quel dominio.

Il tempo necessario per la restituzione di un'entità dipende dalle sue dimensioni, dal carico attualmente in corso sul server e dall'attività di ogni singola macchina tra la macchina che esegue il browser e il server. L'elenco di queste macchine può in linea di principio essere diverso per ogni richiesta, nella misura in cui un'immagine potrebbe viaggiare dagli Stati Uniti a me nel Regno Unito sull'Atlantico, mentre un'altra dallo stesso server esce attraverso il Pacifico, l'Asia e l'Europa, che richiede più tempo. Quindi potresti ottenere una sequenza come la seguente, in cui una pagina ha (in questo ordine) riferimenti a tre file di script e cinque file di immagini, tutti di dimensioni diverse:

  1. OTTIENI script1 e script2; richiesta di coda per script3 e immagini1-5.
  2. arriva script2 (è più piccolo di script1): OTTIENI script3, immagini in coda1-5.
  3. script1 arriva; OTTIENI immagine1, immagini in coda2-5.
  4. immagine1 arriva, OTTIENI immagine2, coda immagini3-5.
  5. script3 non arriva a causa di un problema di rete - OTTIENI di nuovo script3 (nuovo tentativo automatico).
  6. image2 arriva, script3 non è ancora qui; OTTIENI immagine3, immagini in coda4-5.
  7. arriva l'immagine 3; OTTIENI image4, coda image5, script3 ancora in arrivo.
  8. image4 arriva, OTTIENI image5;
  9. image5 arriva.
  10. script3 arriva.

In breve: qualsiasi vecchio ordine, a seconda di cosa sta facendo il server, cosa sta facendo il resto di Internet e se qualcosa ha degli errori e deve essere recuperato. Questo può sembrare un modo strano di fare le cose, ma sarebbe letteralmente impossibile per Internet (non solo il WWW) lavorare con qualsiasi grado di affidabilità se non fosse fatto in questo modo.

Inoltre, la coda interna del browser potrebbe non recuperare le entità nell'ordine in cui appaiono nella pagina - non è richiesto da nessuno standard.

(Oh, e non dimenticare la memorizzazione nella cache, sia nel browser che nei proxy di cache utilizzati dagli ISP per facilitare il carico sulla rete.)



2

AFAIK, il browser (almeno Firefox) richiede ogni risorsa non appena la analizza. Se incontra un tag img, richiederà quell'immagine non appena il tag img è stato analizzato. E questo può accadere anche prima che abbia ricevuto la totalità del documento HTML ... è che potrebbe comunque scaricare il documento HTML quando ciò accade.

Per Firefox, ci sono code del browser applicabili, a seconda di come sono impostate in about: config. Ad esempio, non tenterà di scaricare più di 8 file contemporaneamente dallo stesso server ... le richieste aggiuntive verranno messe in coda. Penso che ci siano limiti per dominio, limiti per proxy e altre cose, che sono documentati sul sito Web di Mozilla e possono essere impostati in: config. Ho letto da qualche parte che IE non ha tali limiti.

L'evento jQuery ready viene generato non appena il documento HTML principale è stato scaricato ed è analizzato DOM. Quindi l'evento load viene generato una volta scaricate e analizzate anche tutte le risorse collegate (CSS, immagini, ecc.). È chiarito nella documentazione di jQuery.

Se vuoi controllare l'ordine in cui tutto ciò che viene caricato, credo che il modo più affidabile per farlo sia tramite JavaScript.



1

La risposta scelta sembra non si applica ai browser moderni, almeno su Firefox 52. Quello che ho osservato è che le richieste di caricamento di risorse come CSS, JavaScript sono emesse prima che il parser HTML raggiunga l'elemento, ad esempio

<html>
  <head>
    <!-- prints the date before parsing and blocks HTMP parsering -->
    <script>
      console.log("start: " + (new Date()).toISOString());
      for(var i=0; i<1000000000; i++) {};
    </script>

    <script src="jquery.js" type="text/javascript"></script>
    <script src="abc.js" type="text/javascript"></script>
    <link rel="stylesheets" type="text/css" href="abc.css"></link>
    <style>h2{font-wight:bold;}</style>
    <script>
      $(document).ready(function(){
      $("#img").attr("src", "kkk.png");
     });
   </script>
 </head>
 <body>
   <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
   <script src="kkk.js" type="text/javascript"></script>
   </body>
</html>

Cosa ho scoperto che l'ora di inizio delle richieste per caricare risorse CSS e JavaScript non era bloccata. Sembra che Firefox abbia una scansione HTML e identifichi le risorse chiave (la risorsa img non è inclusa) prima di iniziare ad analizzare l'HTML.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.