¿Secuencia de carga y ejecución de una página web?

244

He realizado algunos proyectos basados ​​en la web, pero no pienso demasiado en la secuencia de carga y ejecución de una página web ordinaria. Pero ahora necesito saber detalles. Es difícil encontrar respuestas de Google o SO, así que creé esta pregunta.

Una página de muestra es así:

<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>

Asi que aqui están mis preguntas:

  1. ¿Cómo se carga esta página?
  2. ¿Cuál es la secuencia de la carga?
  3. ¿Cuándo se ejecuta el código JS? (en línea y externo)
  4. ¿Cuándo se ejecuta (aplica) el CSS?
  5. ¿Cuándo se ejecuta $ (document) .ready?
  6. ¿Se descargará abc.jpg? ¿O simplemente descarga kkk.png?

Tengo el siguiente entendimiento:

  1. El navegador carga el html (DOM) al principio.
  2. El navegador comienza a cargar los recursos externos de arriba a abajo, línea por línea.
  3. Si <script>se cumple con una, la carga se bloqueará y espere hasta que el archivo JS se cargue y ejecute y luego continúe.
  4. Otros recursos (CSS / imágenes) se cargan en paralelo y se ejecutan si es necesario (como CSS).

O es así:

El navegador analiza el html (DOM) y obtiene los recursos externos en una matriz o estructura tipo pila. Después de cargar el HTML, el navegador comienza a cargar los recursos externos en la estructura en paralelo y ejecutar, hasta que se cargan todos los recursos. Luego, se cambiará el DOM correspondiente a los comportamientos del usuario dependiendo del JS.

¿Alguien puede dar una explicación detallada sobre lo que sucede cuando obtiene la respuesta de una página html? ¿Esto varía en diferentes navegadores? ¿Alguna referencia sobre esta pregunta?

Gracias.

EDITAR:

Hice un experimento en Firefox con Firebug. Y se muestra como la siguiente imagen: texto alternativo

Zhu Tao
fuente
11
Steve Souders ha hecho un gran trabajo en este campo. Google para steve + souders + alto + rendimiento y echar un vistazo.
anddoutoi el
3
No me refiero al ajuste de rendimiento. Quiero saber el detalle.
Zhu Tao
2
Al leer su trabajo, mi comprensión de cómo funciona "en detalle" aumentó diez veces, por lo que sigue siendo un comentario válido. Los derechos de autor no me permiten citar todo su libro aquí, así que aún le sugiero que busque su trabajo.
anddoutoi el
3
Una gran descripción del orden en que suceden las cosas está aquí
Gerrat

Respuestas:

277

De acuerdo a su muestra,

<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>

aproximadamente el flujo de ejecución es aproximadamente como sigue:

  1. El documento HTML se descarga
  2. Comienza el análisis del documento HTML
  3. El análisis HTML alcanza <script src="jquery.js" ...
  4. jquery.js se descarga y analiza
  5. El análisis HTML alcanza <script src="abc.js" ...
  6. abc.js se descarga, analiza y ejecuta
  7. El análisis HTML alcanza <link href="abc.css" ...
  8. abc.css se descarga y analiza
  9. El análisis HTML alcanza <style>...</style>
  10. Las reglas internas de CSS se analizan y definen
  11. El análisis HTML alcanza <script>...</script>
  12. Javascript interno se analiza y ejecuta
  13. El análisis HTML alcanza <img src="abc.jpg" ...
  14. abc.jpg se descarga y se muestra
  15. El análisis HTML alcanza <script src="kkk.js" ...
  16. kkk.js se descarga, analiza y ejecuta
  17. El análisis del documento HTML finaliza

Tenga en cuenta que la descarga puede ser asíncrona y no bloqueante debido a los comportamientos del navegador. Por ejemplo, en Firefox existe esta configuración que limita el número de solicitudes simultáneas por dominio.

Además, dependiendo de si el componente ya se ha almacenado en caché o no, es posible que no se vuelva a solicitar el componente en una solicitud futura. Si el componente se ha almacenado en caché, el componente se cargará desde la memoria caché en lugar de la URL real.

Cuando finaliza el análisis y el documento está listo y cargado, se activan los eventos onload. Por lo tanto, cuando onloadse dispara, $("#img").attr("src","kkk.png");se ejecuta. Entonces:

  1. El documento está listo, se dispara la carga.
  2. Aciertos de ejecución de Javascript $("#img").attr("src", "kkk.png");
  3. kkk.png se descarga y se carga en #img

El $(document).ready()evento es en realidad el evento que se dispara cuando todos los componentes de la página están cargados y listos. Lea más sobre esto: http://docs.jquery.com/Tutorials:Introducing_$ (document) .ready ()

Editar: esta parte elabora más sobre la parte paralela o no:

De manera predeterminada, y según mi conocimiento actual, el navegador generalmente ejecuta cada página de 3 formas: analizador HTML, Javascript / DOM y CSS.

El analizador HTML es responsable de analizar e interpretar el lenguaje de marcado y, por lo tanto, debe poder realizar llamadas a los otros 2 componentes.

Por ejemplo, cuando el analizador se encuentra con esta línea:

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

El analizador realizará 3 llamadas, dos a Javascript y una a CSS. En primer lugar, el analizador creará este elemento y lo registrará en el espacio de nombres DOM, junto con todos los atributos relacionados con este elemento. En segundo lugar, el analizador llamará para vincular el evento onclick a este elemento en particular. Por último, hará otra llamada al hilo CSS para aplicar el estilo CSS a este elemento en particular.

La ejecución es de arriba hacia abajo y de un solo hilo. Javascript puede parecer multiproceso, pero el hecho es que Javascript es de un solo subproceso. Es por eso que al cargar un archivo javascript externo, se suspende el análisis de la página HTML principal.

Sin embargo, los archivos CSS se pueden descargar simultáneamente porque las reglas CSS siempre se aplican, lo que significa que los elementos siempre se repintan con las reglas CSS más recientes definidas, lo que hace que se desbloquee.

Un elemento solo estará disponible en el DOM después de que se haya analizado. Por lo tanto, cuando se trabaja con un elemento específico, el script siempre se coloca después o dentro del evento de carga de la ventana.

Un script como este causará un error (en jQuery):

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

Porque cuando se analiza el script, el #mydivelemento aún no está definido. En cambio, esto funcionaría:

<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>
mauris
fuente
44
Gracias. Pero mencionó que la descarga puede ser asincrónica y no bloqueante debido al comportamiento del navegador , entonces, ¿qué tipo de componentes se pueden descargar en asyn (tome FF como una instancia)? <script>bloqueará otros componentes, ¿verdad? ¿Alguna referencia sobre la especificación de cada navegador?
Zhu Tao
44
$ (document) .ready () se dispara cuando se completa el DOM, no cuando se cargan todos los componentes de la página
Pierre
2
@Pierre por componentes de página me refería al DOM -> cualesquiera componentes en el DOM.
mauris
3
solo para aclarar ... window.onload normal ocurre después del # 17 ... entonces, ¿en qué # se ejecuta el código de jquery's $ (document) .ready ()? # 12? pero el DOM en sí está cargado en el # 1 ¿verdad?
armyofda12mnkeys
1
Si está en la pestaña <body>, si agregamos un <link href = "bootstrap.min.css" rel = "stylesheet" /> entre la etiqueta <img> y <script>, entonces img no se muestra hasta que bootsrap se descargue ... así que creo que los pasos [13], [14] necesitan modificaciones ... ¿alguien puede explicar ese comportamiento?
Bhuvan
34

1) Se descarga HTML.

2) HTML se analiza progresivamente. Cuando se llega a una solicitud de un activo, el navegador intentará descargar el activo. Una configuración predeterminada para la mayoría de los servidores HTTP y la mayoría de los navegadores es procesar solo dos solicitudes en paralelo. IE se puede reconfigurar para descargar una cantidad ilimitada de activos en paralelo. Steve Souders ha podido descargar más de 100 solicitudes en paralelo en IE. La excepción es que las solicitudes de script bloquean las solicitudes de activos paralelos en IE. Es por eso que se recomienda encarecidamente colocar todo JavaScript en archivos externos de JavaScript y colocar la solicitud justo antes de cerrar la etiqueta del cuerpo en el HTML.

3) Una vez que se analiza el HTML, se representa el DOM. CSS se representa en paralelo a la representación del DOM en casi todos los agentes de usuario. Como resultado, se recomienda encarecidamente colocar todo el código CSS en archivos CSS externos que se soliciten lo más alto posible en la sección <head> </head> del documento. De lo contrario, la página se representa hasta que se produce la posición de solicitud CSS en el DOM y luego la representación comienza desde la parte superior.

4) Solo después de que el DOM se procesa por completo y las solicitudes de todos los activos en la página se resuelven o se agota el tiempo de espera, JavaScript se ejecuta desde el evento de carga. IE7, y no estoy seguro acerca de IE8, no agota los recursos rápidamente si no se recibe una respuesta HTTP de la solicitud de activos. Esto significa que un activo solicitado por JavaScript en línea en la página, es decir, JavaScript escrito en etiquetas HTML que no está contenido en una función, puede evitar la ejecución del evento de carga durante horas. Este problema se puede desencadenar si dicho código en línea existe en la página y no se ejecuta debido a una colisión en el espacio de nombres que provoca un bloqueo del código.

De los pasos anteriores, el que requiere más CPU es el análisis del DOM / CSS. Si desea que su página se procese más rápido, escriba CSS eficiente eliminando instrucciones redundantes y consolidando las instrucciones CSS en la menor cantidad posible de referencias de elementos. Reducir el número de nodos en su árbol DOM también producirá una representación más rápida.

Tenga en cuenta que cada activo que solicite de su HTML o incluso de sus activos CSS / JavaScript se solicita con un encabezado HTTP separado. Esto consume ancho de banda y requiere procesamiento por solicitud. Si desea que su página se cargue lo más rápido posible, reduzca la cantidad de solicitudes HTTP y el tamaño de su HTML. No está haciendo ningún favor a su experiencia de usuario al promediar el peso de la página a 180k solo con HTML. Muchos desarrolladores se suscriben a una falacia de que un usuario toma una decisión sobre la calidad del contenido de la página en 6 nanosegundos y luego purga la consulta DNS de su servidor y quema su computadora si no está satisfecho, por lo que en su lugar proporcionan la página más hermosa posible en 250k de HTML. Mantenga su HTML corto y agradable para que un usuario pueda cargar sus páginas más rápido.


fuente
2
consolidar las instrucciones CSS en la menor cantidad posible de referencias de elementos. Suena raro. Si necesito diseñar tres elementos, necesito hacer referencia exactamente a tres elementos. No puedo hacer referencia al estilo diez, ¿verdad? O explique sobre eso
Green
12

Abra su página en Firefox y obtenga el complemento HTTPFox. Te dirá todo lo que necesitas.

Encontré esto en archivist.incuito:

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

Cuando solicita una página por primera vez, su navegador envía una solicitud GET al servidor, que devuelve el HTML al navegador. El navegador comienza a analizar la página (posiblemente antes de que se haya devuelto todo).

Cuando encuentra una referencia a una entidad externa, como un archivo CSS, un archivo de imagen, un archivo de script, un archivo Flash o cualquier otra cosa externa a la página (ya sea en el mismo servidor / dominio o no), se prepara para hacer otra solicitud GET para ese recurso.

Sin embargo, el estándar HTTP especifica que el navegador no debe realizar más de dos solicitudes simultáneas al mismo dominio. Por lo tanto, coloca cada solicitud en un dominio particular en una cola, y cuando se devuelve cada entidad, comienza la siguiente en la cola para ese dominio.

El tiempo que demora la devolución de una entidad depende de su tamaño, la carga que el servidor está experimentando actualmente y la actividad de cada máquina entre la máquina que ejecuta el navegador y el servidor. La lista de estas máquinas puede ser, en principio, diferente para cada solicitud, en la medida en que una imagen pueda viajar de Estados Unidos a mí en el Reino Unido sobre el Atlántico, mientras que otra del mismo servidor sale a través del Pacífico, Asia y Europa, Que lleva más tiempo. Por lo tanto, puede obtener una secuencia como la siguiente, donde una página tiene (en este orden) referencias a tres archivos de script y cinco archivos de imagen, todos de diferentes tamaños:

  1. GET script1 y script2; Solicitud de cola para script3 e imágenes1-5.
  2. llega script2 (es más pequeño que script1): OBTENER script3, poner en cola las imágenes1-5.
  3. script1 llega; OBTENER imagen1, imágenes de cola2-5.
  4. llega image1, GET image2, cola images3-5.
  5. script3 no llega debido a un problema de red - OBTENGA script3 nuevamente (reintento automático).
  6. llega image2, script3 todavía no está aquí; OBTENER imagen3, imágenes de cola 4-5.
  7. llega la imagen 3; GET image4, queue image5, script3 todavía en camino.
  8. llega image4, OBTENGA image5;
  9. llega image5.
  10. llega script3.

En resumen: cualquier orden anterior, según lo que esté haciendo el servidor, lo que esté haciendo el resto de Internet y si algo tiene errores o no y debe volver a buscarse. Esto puede parecer una forma extraña de hacer las cosas, pero literalmente sería imposible que Internet (no solo WWW) funcione con algún grado de confiabilidad si no se hiciera de esta manera.

Además, es posible que la cola interna del navegador no obtenga entidades en el orden en que aparecen en la página; ningún estándar lo requiere.

(Ah, y no olvide el almacenamiento en caché, tanto en el navegador como en los servidores proxy utilizados por los ISP para facilitar la carga en la red).

tahdhaze09
fuente
6

Si está preguntando esto porque quiere acelerar su sitio web, consulte la página de Yahoo en Mejores prácticas para acelerar su sitio web . Tiene muchas mejores prácticas para acelerar su sitio web.

un nerd pagado
fuente
2

AFAIK, el navegador (al menos Firefox) solicita cada recurso tan pronto como lo analiza. Si encuentra una etiqueta img, solicitará esa imagen tan pronto como se haya analizado la etiqueta img. Y eso puede ser incluso antes de que haya recibido la totalidad del documento HTML ... es decir, podría estar descargando el documento HTML cuando eso suceda.

Para Firefox, hay colas de navegador que se aplican, dependiendo de cómo estén configuradas en about: config. Por ejemplo, no intentará descargar más de 8 archivos a la vez desde el mismo servidor ... las solicitudes adicionales se pondrán en cola. Creo que hay límites por dominio, por límites de proxy y otras cosas, que están documentadas en el sitio web de Mozilla y se pueden configurar en about: config. Leí en alguna parte que IE no tiene tales límites.

El evento jQuery ready se activa tan pronto como el documento HTML principal se descarga el y se analiza el DOM. Luego, el evento de carga se activa una vez que todos los recursos vinculados (CSS, imágenes, etc.) también se han descargado y analizado. Se aclara en la documentación de jQuery.

Si desea controlar el orden en que se carga todo eso, creo que la forma más confiable de hacerlo es a través de JavaScript.

Rolf
fuente
1

Parece que la respuesta elegida no se aplica a los navegadores modernos, al menos en Firefox 52. Lo que observé es que las solicitudes de carga de recursos como css, javascript se emiten antes de que el analizador HTML llegue al elemento, por ejemplo

<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>

Lo que encontré fue que el tiempo de inicio de las solicitudes para cargar recursos CSS y JavaScript no estaba bloqueado. Parece que Firefox tiene un escaneo HTML e identifica recursos clave (el recurso img no está incluido) antes de comenzar a analizar el HTML.

Xiaoming
fuente