Carregar e sequência de execução de uma página da web?

244

Eu fiz alguns projetos baseados na Web, mas não penso muito na sequência de carga e execução de uma página da Web comum. Mas agora eu preciso saber detalhes. É difícil encontrar respostas do Google ou do SO, por isso criei esta pergunta.

Uma página de amostra é assim:

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

Então, aqui estão as minhas questões:

  1. Como esta página é carregada?
  2. Qual é a sequência do carregamento?
  3. Quando o código JS é executado? (inline e externo)
  4. Quando o CSS é executado (aplicado)?
  5. Quando o $ (document) .ready é executado?
  6. O abc.jpg será baixado? Ou simplesmente faz o download do kkk.png?

Eu tenho o seguinte entendimento:

  1. O navegador carrega o html (DOM) primeiro.
  2. O navegador começa a carregar os recursos externos de cima para baixo, linha por linha.
  3. Se a <script>for atendido, o carregamento será bloqueado e espere até que o arquivo JS seja carregado e executado e continue.
  4. Outros recursos (CSS / imagens) são carregados em paralelo e executados, se necessário (como CSS).

Ou é assim:

O navegador analisa o html (DOM) e obtém os recursos externos em uma matriz ou estrutura semelhante a uma pilha. Depois que o html é carregado, o navegador começa a carregar os recursos externos na estrutura em paralelo e a executar, até que todos os recursos sejam carregados. Em seguida, o DOM será alterado de acordo com o comportamento do usuário, dependendo do JS.

Alguém pode dar uma explicação detalhada sobre o que acontece quando você recebe a resposta de uma página html? Isso varia em diferentes navegadores? Alguma referência sobre esta questão?

Obrigado.

EDITAR:

Eu fiz um experimento no Firefox com o Firebug. E mostra como a seguinte imagem: texto alternativo

Zhu Tao
fonte
11
Steve Souders fez um grande trabalho neste campo. Google para steve + souders + high + performance e dê uma olhada.
35630 anddoutoi
3
Não quero dizer ajuste de desempenho. Eu quero conhecer os detalhes.
Zhu Tao
2
Ao ler seu trabalho, minha compreensão de como "ele" funciona em detalhes aumentou dez vezes, por isso ainda é um comentário válido. Os direitos autorais não têm permissão para citar o livro inteiro aqui, então ainda sugiro que você procure o trabalho dele.
35630 Anddoutoi
3
Uma ótima descrição da ordem em que as coisas acontecem está aqui
Gerrat 29/05

Respostas:

277

De acordo com sua amostra,

<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 o fluxo de execução é o seguinte:

  1. O documento HTML é baixado
  2. A análise do documento HTML é iniciada
  3. A análise de HTML atinge <script src="jquery.js" ...
  4. jquery.js é baixado e analisado
  5. A análise de HTML atinge <script src="abc.js" ...
  6. abc.js é baixado, analisado e executado
  7. A análise de HTML atinge <link href="abc.css" ...
  8. abc.css é baixado e analisado
  9. A análise de HTML atinge <style>...</style>
  10. Regras internas de CSS são analisadas e definidas
  11. A análise de HTML atinge <script>...</script>
  12. Javascript interno é analisado e executado
  13. A análise de HTML atinge <img src="abc.jpg" ...
  14. abc.jpg é baixado e exibido
  15. A análise de HTML atinge <script src="kkk.js" ...
  16. kkk.js é baixado, analisado e executado
  17. A análise do documento HTML termina

Observe que o download pode ser assíncrono e sem bloqueio devido a comportamentos do navegador. Por exemplo, no Firefox, existe essa configuração que limita o número de solicitações simultâneas por domínio.

Além disso, dependendo de o componente já ter sido armazenado em cache ou não, o componente pode não ser solicitado novamente em uma solicitação no futuro próximo. Se o componente tiver sido armazenado em cache, o componente será carregado a partir do cache, em vez da URL real.

Quando a análise é finalizada e o documento está pronto e carregado, os eventos onloadsão disparados. Assim, quando onloadé acionado, o $("#img").attr("src","kkk.png");é executado. Assim:

  1. O documento está pronto, o onload é acionado.
  2. Resultados de execução de Javascript $("#img").attr("src", "kkk.png");
  3. kkk.png é baixado e carregado em #img

O $(document).ready()evento é realmente o evento disparado quando todos os componentes da página estão carregados e prontos. Leia mais sobre o assunto: http://docs.jquery.com/Tutorials:Introducing_$ (document) .ready ()

Editar - Esta parte elabora mais a parte paralela ou não:

Por padrão, e do meu entendimento atual, o navegador geralmente executa cada página de três maneiras: analisador de HTML, Javascript / DOM e CSS.

O analisador HTML é responsável por analisar e interpretar a linguagem de marcação e, portanto, deve poder fazer chamadas para os outros 2 componentes.

Por exemplo, quando o analisador se depara com esta linha:

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

O analisador fará três chamadas, duas para Javascript e uma para CSS. Primeiro, o analisador criará esse elemento e o registrará no espaço para nome DOM, juntamente com todos os atributos relacionados a esse elemento. Em segundo lugar, o analisador chamará para vincular o evento onclick a esse elemento específico. Por fim, ele fará outra chamada ao segmento CSS para aplicar o estilo CSS a esse elemento específico.

A execução é descendente e única encadeada. O Javascript pode parecer multiencadeado, mas o fato é que o Javascript é único encadeado. É por isso que, ao carregar o arquivo javascript externo, a análise da página HTML principal é suspensa.

No entanto, os arquivos CSS podem ser baixados simultaneamente, porque as regras CSS estão sempre sendo aplicadas - ou seja, os elementos são sempre repintados com as regras CSS mais recentes definidas - tornando-o desbloqueado.

Um elemento estará disponível apenas no DOM depois de ter sido analisado. Portanto, ao trabalhar com um elemento específico, o script é sempre colocado após ou dentro do evento onload da janela.

Script como este causará erro (no jQuery):

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

Porque quando o script é analisado, o #mydivelemento ainda não está definido. Em vez disso, isso funcionaria:

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

OU

<script type="text/javascript">/* <![CDATA[ */
  $(window).ready(function(){
                    alert($("#mydiv").html());
                  });
/* ]]> */</script>
<div id="mydiv">Hello World</div>
mauris
fonte
4
obrigado. Mas você mencionou que o download pode ser assíncrono e sem bloqueio devido aos comportamentos do navegador . Portanto, que tipo de componentes podem ser baixados em assíncrono (tome o FF como uma instância)? <script>vai bloquear outros componentes, certo? Alguma referência sobre as especificações para cada navegador?
Zhu Tao
4
$ (document) .ready () é acionado quando o DOM está completo, não quando todos os componentes da página são carregados
Pierre
2
@Pierre por componentes da página, eu quis dizer o DOM -> quaisquer componentes no DOM.
mauris
3
só para esclarecer ... window.onload regular acontece após o # 17 ... então, em que # o código $ (document) .ready () do jquery é executado? 12? mas o próprio DOM é carregado em # 1, certo?
Armyofda12mnkeys 27/05
1
Se na guia <body>, se adicionarmos um <link href = "bootstrap.min.css" rel = "stylesheet" /> entre as tags <img> e <script>, o img não será exibido até que o bootrap seja baixado ... então eu acho que a etapa [13], [14] precisa ser modificada ... alguém pode explicar esse comportamento?
Bhuvan 29/10/2015
34

1) HTML é baixado.

2) HTML é analisado progressivamente. Quando uma solicitação de um ativo é alcançada, o navegador tenta fazer o download do ativo. Uma configuração padrão para a maioria dos servidores HTTP e a maioria dos navegadores é processar apenas duas solicitações em paralelo. O IE pode ser reconfigurado para baixar um número ilimitado de ativos em paralelo. Steve Souders conseguiu baixar mais de 100 solicitações em paralelo no IE. A exceção é que as solicitações de script bloqueiam solicitações de ativos paralelas no IE. É por isso que é altamente recomendável colocar todo o JavaScript em arquivos JavaScript externos e colocar a solicitação antes da tag do corpo de fechamento no HTML.

3) Depois que o HTML é analisado, o DOM é renderizado. O CSS é renderizado em paralelo com a renderização do DOM em quase todos os agentes do usuário. Como resultado, é altamente recomendável colocar todo o código CSS em arquivos CSS externos solicitados o mais alto possível na seção <head> </head> do documento. Caso contrário, a página será renderizada até a ocorrência da posição de solicitação de CSS no DOM e, em seguida, a renderização será iniciada novamente.

4) Somente depois que o DOM for renderizado completamente e as solicitações de todos os ativos da página forem resolvidas ou o tempo limite o JavaScript for executado a partir do evento onload. O IE7, e não tenho certeza sobre o IE8, não atinge o tempo limite dos ativos rapidamente se uma resposta HTTP não for recebida da solicitação de ativo. Isso significa que um ativo solicitado pelo JavaScript embutido na página, que é JavaScript gravado em tags HTML que não estão contidas em uma função, pode impedir a execução do evento onload por horas. Esse problema pode ser disparado se esse código embutido existir na página e falhar na execução devido a uma colisão de namespace que causa uma falha no código.

Das etapas acima, a que consome mais CPU é a análise do DOM / CSS. Se você deseja que sua página seja processada mais rapidamente, escreva CSS eficiente, eliminando instruções redundantes e consolidando instruções CSS no menor número possível de referências de elementos. Reduzir o número de nós na sua árvore DOM também produzirá renderização mais rápida.

Lembre-se de que cada recurso solicitado em seu HTML ou mesmo em CSS / JavaScript é solicitado com um cabeçalho HTTP separado. Isso consome largura de banda e requer processamento por solicitação. Se você deseja fazer com que sua página seja carregada o mais rápido possível, reduza o número de solicitações HTTP e reduza o tamanho do seu HTML. Você não está favorecendo a experiência do usuário calculando a média da ponderação da página em 180k somente a partir do HTML. Muitos desenvolvedores concordam com alguma falácia de que um usuário decide sobre a qualidade do conteúdo da página em 6 nanossegundos e, em seguida, elimina a consulta DNS do servidor e queima o computador se estiver insatisfeito. Portanto, eles fornecem a página mais bonita possível em 250k de HTML. Mantenha seu HTML curto e agradável para que um usuário possa carregar suas páginas mais rapidamente.


fonte
2
consolidar instruções CSS no menor número possível de referências de elementos Parece estranho. Se eu precisar estilizar três elementos, preciso fazer referência exatamente a três elementos. Não posso referenciar um ao estilo dez, posso? Ou elaborar sobre isso #
Green
12

Abra sua página no Firefox e obtenha o complemento HTTPFox. Isso lhe dirá tudo o que você precisa.

Encontrei isso em archivist.incuito:

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

Quando você solicita uma página pela primeira vez, seu navegador envia uma solicitação GET ao servidor, que retorna o HTML ao navegador. O navegador começa a analisar a página (possivelmente antes que tudo tenha sido devolvido).

Quando encontra uma referência a uma entidade externa, como um arquivo CSS, um arquivo de imagem, um arquivo de script, um arquivo Flash ou qualquer outra coisa externa à página (no mesmo servidor / domínio ou não), ele se prepara para fazer uma solicitação GET adicional para esse recurso.

No entanto, o padrão HTTP especifica que o navegador não deve fazer mais de duas solicitações simultâneas para o mesmo domínio. Portanto, coloca cada solicitação em um domínio específico em uma fila e, à medida que cada entidade é retornada, inicia a próxima na fila para esse domínio.

O tempo necessário para o retorno de uma entidade depende do tamanho, da carga que o servidor está passando e da atividade de cada máquina entre a máquina que está executando o navegador e o servidor. A lista dessas máquinas pode, em princípio, ser diferente para cada solicitação, na medida em que uma imagem possa viajar dos EUA para mim no Reino Unido sobre o Atlântico, enquanto outra do mesmo servidor sai pelo Pacífico, Ásia e Europa, o que leva mais tempo. Portanto, você pode obter uma sequência como a seguinte, em que uma página tem (nessa ordem) referências a três arquivos de script e cinco arquivos de imagem, todos com tamanhos diferentes:

  1. GET script1 e script2; solicitação de fila para script3 e images1-5.
  2. chega o script2 (é menor que o script1): GET script3, filas de imagens1-5.
  3. o script1 chega; GET image1, fila images2-5.
  4. image1 chega, GET image2, enfileira images3-5.
  5. script3 falha ao chegar devido a um problema de rede - GET script3 novamente (nova tentativa automática).
  6. a imagem 2 chega, o script3 ainda não está aqui; GET image3, fila images4-5.
  7. a imagem 3 chega; GET imagem4, fila imagem5, script3 ainda a caminho.
  8. imagem4 chega, GET imagem5;
  9. image5 chega.
  10. chega o script3.

Resumindo: qualquer ordem antiga, dependendo do que o servidor está fazendo, do que o resto da Internet está fazendo e se algo tem ou não erros e precisa ser buscado novamente. Isso pode parecer uma maneira estranha de fazer as coisas, mas seria literalmente impossível para a Internet (não apenas a WWW) trabalhar com algum grau de confiabilidade se não fosse assim.

Além disso, a fila interna do navegador pode não buscar entidades na ordem em que aparecem na página - não é exigida por nenhum padrão.

(Ah, e não se esqueça do armazenamento em cache, tanto no navegador quanto nos proxies de armazenamento em cache usados ​​pelos ISPs para facilitar a carga na rede.)

tahdhaze09
fonte
6

Se você está perguntando isso porque deseja acelerar o seu site, consulte a página do Yahoo sobre Práticas recomendadas para acelerar o seu site . Possui muitas práticas recomendadas para acelerar o seu site.

um nerd pago
fonte
2

AFAIK, o navegador (pelo menos Firefox) solicita todos os recursos assim que o analisa. Se encontrar uma tag img, solicitará a imagem assim que a tag img for analisada. E isso pode acontecer antes mesmo de receber a totalidade do documento HTML ... ou seja, ele ainda pode estar baixando o documento HTML quando isso acontecer.

Para o Firefox, existem filas de navegadores que se aplicam, dependendo de como elas são definidas em about: config. Por exemplo, ele não tentará baixar mais de 8 arquivos de uma vez no mesmo servidor ... os pedidos adicionais serão colocados na fila. Eu acho que existem limites por domínio, limites de proxy e outras coisas, que estão documentados no site da Mozilla e podem ser configurados em about: config. Eu li em algum lugar que o IE não tem esses limites.

O evento pronto para jQuery é acionado assim que o documento HTML principal é baixado e é analisado pelo DOM. Em seguida, o evento de carregamento é acionado depois que todos os recursos vinculados (CSS, imagens etc.) também foram baixados e analisados. Isso fica claro na documentação do jQuery.

Se você deseja controlar a ordem na qual tudo é carregado, acredito que a maneira mais confiável de fazer isso é através do JavaScript.

Rolf
fonte
1

O Dynatrace AJAX Edition mostra a sequência exata de carregamento, análise e execução de páginas.

Chetan S
fonte
1

A resposta escolhida parece não se aplicar a navegadores modernos, pelo menos no Firefox 52. O que observei é que as solicitações de carregamento de recursos como css, javascript são emitidas antes que o analisador HTML atinja o elemento, por exemplo

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

O que descobri que a hora de início das solicitações para carregar recursos css e javascript não estava sendo bloqueada. Parece que o Firefox tem uma verificação em HTML e identifica os principais recursos (o recurso img não está incluído) antes de começar a analisar o HTML.

Xiaoming
fonte