O CSS sempre deve preceder o Javascript?


897

Em inúmeros locais online, vi a recomendação de incluir CSS antes do JavaScript. O raciocínio é geralmente, desta forma :

Quando se trata de pedir seu CSS e JavaScript, você deseja que seu CSS seja o primeiro. O motivo é que o encadeamento de renderização possui todas as informações de estilo necessárias para renderizar a página. Se o JavaScript incluir o primeiro, o mecanismo JavaScript precisará analisar tudo antes de continuar no próximo conjunto de recursos. Isso significa que o encadeamento de renderização não pode mostrar completamente a página, pois não possui todos os estilos necessários.

Meu teste real revela algo bem diferente:

Meu equipamento de teste

Eu uso o seguinte script Ruby para gerar atrasos específicos para vários recursos:

require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
require 'date'

class Handler  < EventMachine::Connection
  include EventMachine::HttpServer

  def process_http_request
    resp = EventMachine::DelegatedHttpResponse.new( self )

    return unless @http_query_string

    path = @http_path_info
    array = @http_query_string.split("&").map{|s| s.split("=")}.flatten
    parsed = Hash[*array]

    delay = parsed["delay"].to_i / 1000.0
    jsdelay = parsed["jsdelay"].to_i

    delay = 5 if (delay > 5)
    jsdelay = 5000 if (jsdelay > 5000)

    delay = 0 if (delay < 0) 
    jsdelay = 0 if (jsdelay < 0)

    # Block which fulfills the request
    operation = proc do
      sleep delay 

      if path.match(/.js$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/javascript"
        resp.content = "(function(){
            var start = new Date();
            while(new Date() - start < #{jsdelay}){}
          })();"
      end
      if path.match(/.css$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/css"
        resp.content = "body {font-size: 50px;}"
      end
    end

    # Callback block to execute once the request is fulfilled
    callback = proc do |res|
        resp.send_response
    end

    # Let the thread pool (20 Ruby threads) handle request
    EM.defer(operation, callback)
  end
end

EventMachine::run {
  EventMachine::start_server("0.0.0.0", 8081, Handler)
  puts "Listening..."
}

O mini servidor acima permite definir atrasos arbitrários para arquivos JavaScript (servidor e cliente) e atrasos arbitrários em CSS. Por exemplo, http://10.0.0.50:8081/test.css?delay=500me dá um atraso de 500 ms na transferência do CSS.

Eu uso a página a seguir para testar.

<!DOCTYPE html>
<html>
  <head>
      <title>test</title>
      <script type='text/javascript'>
          var startTime = new Date();
      </script>
      <link href="http://10.0.0.50:8081/test.css?delay=500" type="text/css" rel="stylesheet">
      <script type="text/javascript" src="http://10.0.0.50:8081/test2.js?delay=400&amp;jsdelay=1000"></script> 
  </head>
  <body>
    <p>
      Elapsed time is: 
      <script type='text/javascript'>
        document.write(new Date() - startTime);
      </script>
    </p>    
  </body>
</html>

Quando incluo o CSS primeiro, a página leva 1,5 segundos para renderizar:

CSS primeiro

Quando incluo o JavaScript primeiro, a página leva 1,4 segundos para renderizar:

JavaScript primeiro

Eu obtenho resultados semelhantes no Chrome, Firefox e Internet Explorer. No Opera, no entanto, a ordenação simplesmente não importa.

O que parece estar acontecendo é que o intérprete JavaScript se recusa a iniciar até que todo o CSS seja baixado. Portanto, parece que ter o JavaScript incluído primeiro é mais eficiente, pois o encadeamento do JavaScript ganha mais tempo de execução.

Estou faltando alguma coisa, a recomendação para colocar CSS inclui antes de JavaScript não está correta?

É claro que poderíamos adicionar async ou usar setTimeout para liberar o encadeamento de renderização ou colocar o código JavaScript no rodapé ou usar um carregador JavaScript. O ponto aqui é sobre a ordenação de bits JavaScript essenciais e CSS na cabeça.


120
1511 vs 1422 é uma diferença estatisticamente significativa? Isso é 6%. O limiar geral para a diferença de desempenho humano notável a médio é de cerca de 20%.
21412 Jeff Atwood

15
o ponto é que a reordenação elimina esse atraso arbitrário; você pode configurá-lo para o que quiser, é apenas uma demonstração do problema.
Sam Saffron

3
seu atraso foi de 100ms? a diferença nas suas capturas de tela é 89ms. Na sua URL, ela está delay=400&amp;jsdelay=1000e delay=500nem chega a 100ms ou 89ms. Acho que não estou claro a quais números você está se referindo.
21412 Jeff Atwood

4
"Se o Javascript incluir primeiro, o mecanismo Javascript precisará analisar tudo antes de continuar para o próximo conjunto de recursos. Isso significa que o encadeamento de renderização não pode mostrar completamente a página, pois não possui todos os estilos necessários. . " - se o JS include estiver na cabeça, o JS será executado antes da página ser renderizada, independentemente de o CSS include ter sido anterior ou posterior.
Nnnnnn

162
Não tenho certeza se você considerou isso, mas a percepção do tempo de carregamento também é importante. Assim, por exemplo, se o carregamento do CSS fornecer apenas a cor / textura do plano de fundo da página, pareceria mais rápido. Os tempos de carregamento absolutos podem não ser indicativos disso.
Rakesh Pai

Respostas:


712

Esta é uma questão muito interessante. Eu sempre coloquei meus CSS <link href="...">antes dos JS <script src="...">porque "Li uma vez que é melhor". Então, você está certo; é hora de fazermos uma pesquisa real!

Eu configurei meu próprio equipamento de teste no Nó (código abaixo). Basicamente, eu:

  • Certifique-se de que não haja cache HTTP, para que o navegador precise fazer um download completo cada vez que uma página for carregada.
  • Para simular a realidade, incluí o jQuery e o CSS do H5BP (para que haja uma quantidade decente de script / CSS para analisar)
  • Configure duas páginas - uma com CSS antes do script e outra com CSS após o script.
  • Registrou quanto tempo levou para o script externo <head>executar
  • Registrou quanto tempo levou para o script embutido na <body>execução, o que é análogo DOMReady.
  • Atraso no envio de CSS e / ou script para o navegador em 500ms.
  • Execute o teste 20 vezes nos 3 principais navegadores.

Resultados

Primeiro, com o arquivo CSS atrasado em 500ms:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 583ms  36ms  | 559ms  42ms  | 565ms 49ms
St Dev      | 15ms   12ms  | 9ms    7ms   | 13ms  6ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 584ms  521ms | 559ms  513ms | 565ms 519ms
St Dev      | 15ms   9ms   | 9ms    5ms   | 13ms  7ms

Em seguida, defino o jQuery para atrasar 500ms em vez do CSS:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 597ms  556ms | 562ms  559ms | 564ms 564ms
St Dev      | 14ms   12ms  | 11ms   7ms   | 8ms   8ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 598ms  557ms | 563ms  560ms | 564ms 565ms
St Dev      | 14ms   12ms  | 10ms   7ms   | 8ms   8ms

Por fim, defino o jQuery e o CSS para atrasar em 500ms:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 620ms  560ms | 577ms  577ms | 571ms 567ms
St Dev      | 16ms   11ms  | 19ms   9ms   | 9ms   10ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 623ms  561ms | 578ms  580ms | 571ms 568ms
St Dev      | 18ms   11ms  | 19ms   9ms   | 9ms   10ms

Conclusões

Primeiro, é importante observar que estou operando sob a suposição de que você possui scripts localizados no <head>documento (em oposição ao final do <body>). Existem vários argumentos sobre o motivo pelo qual você pode vincular seus scripts no <head>final do documento, mas isso está fora do escopo desta resposta. Isso é estritamente sobre se <script>s deve ir antes de <link>s no <head>.

Nos navegadores DESKTOP modernos, parece que vincular ao CSS primeiro nunca fornece um ganho de desempenho. Colocar CSS após o script gera um ganho trivial quando o CSS e o script estão atrasados, mas oferece grandes ganhos quando o CSS está atrasado. (Mostrado pelas lastcolunas no primeiro conjunto de resultados.)

Dado que a vinculação ao último CSS não parece prejudicar o desempenho, mas pode proporcionar ganhos em determinadas circunstâncias, você deve vincular a folhas de estilo externas depois de vincular a scripts externos apenas em navegadores de desktop, se o desempenho de navegadores antigos não for uma preocupação. Leia sobre a situação móvel.

Por quê?

Historicamente, quando um navegador encontrava uma <script>tag apontando para um recurso externo, o navegador parava de analisar o HTML, recuperava o script, executava-o e continuava analisando o HTML. Por outro lado, se o navegador encontrasse um <link>para uma folha de estilo externa, continuaria analisando o HTML enquanto buscava o arquivo CSS (em paralelo).

Portanto, os conselhos amplamente repetidos para colocar as folhas de estilo em primeiro lugar - eles seriam baixados primeiro e o primeiro script a ser baixado poderia ser carregado em paralelo.

No entanto, navegadores modernos (incluindo todos os navegadores testados acima) implementaram a análise especulativa , em que o navegador "olha para a frente" no HTML e começa a baixar recursos antes de os scripts serem baixados e executados.

Em navegadores antigos sem análise especulativa, a colocação de scripts em primeiro lugar afetará o desempenho, pois eles não serão baixados em paralelo.

Suporte do navegador

A análise especulativa foi implementada pela primeira vez em: (junto com a porcentagem de usuários mundiais de navegadores de desktop que usam esta versão ou superior em janeiro de 2012)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3,5 (96%)
  • Safari 4 (99%)
  • Opera 11.60 (85%)

No total, aproximadamente 85% dos navegadores de desktop em uso atualmente suportam carregamento especulativo. Colocar scripts antes do CSS terá uma penalidade de desempenho em 15% dos usuários em todo o mundo ; YMMV com base no público específico do seu site. (E lembre-se de que o número está diminuindo.)

Nos navegadores móveis, é um pouco mais difícil obter números definitivos simplesmente devido à heterogeneidade do navegador móvel e do cenário do sistema operacional. Como a renderização especulativa foi implementada no WebKit 525 (lançado em março de 2008) e praticamente todos os navegadores móveis que valem a pena são baseados no WebKit, podemos concluir que "a maioria" dos navegadores móveis deve suportá-lo. De acordo com o quirksmode , o iOS 2.2 / Android 1.0 usa o WebKit 525. Não tenho idéia de como é o Windows Phone.

No entanto, eu executei o teste no meu dispositivo Android 4 e, enquanto vi números semelhantes aos resultados da área de trabalho, liguei-o ao fantástico novo depurador remoto no Chrome para Android, e a guia Rede mostrou que o navegador estava realmente esperando para baixar o CSS até que os JavaScripts sejam completamente carregados - em outras palavras, mesmo a versão mais recente do WebKit para Android não parece suportar análise especulativa. Eu suspeito que ele possa estar desativado devido às restrições de CPU, memória e / ou rede inerentes aos dispositivos móveis.

Código

Perdoe a negligência - este foi o Q&D.

app.js

var express = require('express')
, app = express.createServer()
, fs = require('fs');

app.listen(90);

var file={};
fs.readdirSync('.').forEach(function(f) {
    console.log(f)
    file[f] = fs.readFileSync(f);
    if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) {
        res.contentType(f);
        res.send(file[f]);
    });
});


app.get('/jquery.js', function(req,res) {
    setTimeout(function() {
        res.contentType('text/javascript');
        res.send(file['jquery.js']);
    }, 500);
});

app.get('/style.css', function(req,res) {
    setTimeout(function() {
        res.contentType('text/css');
        res.send(file['style.css']);
    }, 500);
});


var headresults={
    css: [],
    js: []
}, bodyresults={
    css: [],
    js: []
}
app.post('/result/:type/:time/:exec', function(req,res) {
    headresults[req.params.type].push(parseInt(req.params.time, 10));
    bodyresults[req.params.type].push(parseInt(req.params.exec, 10));
    res.end();
});

app.get('/result/:type', function(req,res) {
    var o = '';
    headresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    o+='\n';
    bodyresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    res.send(o);
});

css.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <link rel="stylesheet" href="style.css">
        <script src="jquery.js"></script>
        <script src="test.js"></script>
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

js.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <script src="jquery.js"></script>
        <script src="test.js"></script>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

test.js

var jsload = Date.now();


$(function() {
    $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start));
});

O jquery.js era o jquery-1.7.1.min.js


137
Esta é uma resposta fantástica, obrigado por usar a ciência! De acordo com o seu resultado "em navegadores modernos, parece que vincular ao CSS nunca fornece um ganho de desempenho" , acho que a resposta ao título da pergunta é sim , o antigo conselho do CSS é claramente inválido.
21412 Jeff Atwood

Em relação à atualização do @ josh3736 sobre o inverso no celular ... esse é um caso para não dar o fora nessa mudança significativa. Eu ficaria curioso para saber como outros navegadores móveis se comportam (webkit, gecko, presto, tridente etc.), pois o desempenho em dispositivos móveis costuma ser mais importante.
scunliffe

1
Você também deve tentar adicionar um pouco de lentidão para imprimir o css / js, para simular a velocidade de um servidor lento.
22412 kirb

1
"Primeiro, é importante observar que estou operando sob a suposição de que você possui scripts localizados no <head>seu documento (em oposição ao final do <body>)." Eu destacaria isso muito antes na resposta, como no topo. Incluir um scriptno headque se refere a um arquivo externo quase nunca é correto, de quase qualquer perspectiva (certamente não de desempenho). Não me lembro de ter feito isso na vida real. A linha ímpar ou duas do script embutido talvez, mas é tudo. O padrão, sem muito boas razões contrárias, deve ser o fim do corpo.
TJ Crowder

1
Com voto negativo, o jQuery não é JavaScript e apenas incha a página, portanto, os resultados usando ela não são objetivos.
John

303

Existem dois motivos principais para colocar o CSS antes do JavaScript.

  1. Navegadores antigos (Internet Explorer 6-7, Firefox 2 etc.) bloqueariam todos os downloads subsequentes quando eles começassem a baixar um script. Portanto, se você a.jsseguiu, b.csseles são baixados sequencialmente: primeiro a então b. Se você b.cssseguiu, a.jseles são baixados em paralelo para que a página seja carregada mais rapidamente.

  2. Nada é renderizado até que todas as folhas de estilo sejam baixadas - isso é verdade em todos os navegadores. Os scripts são diferentes - eles bloqueiam a renderização de todos os elementos DOM que estão abaixo da tag de script na página. Se você colocar seus scripts no HEAD, significa que a página inteira ficará impedida de renderizar até que todas as folhas de estilo e todos os scripts sejam baixados. Embora faça sentido bloquear toda a renderização para folhas de estilo (para que você obtenha o estilo correto na primeira vez e evite o flash do conteúdo sem estilo FOUC), não faz sentido bloquear a renderização da página inteira para scripts. Geralmente, os scripts não afetam nenhum elemento DOM ou apenas uma parte dos elementos DOM. É melhor carregar scripts o mais baixo possível na página, ou melhor ainda, carregá-los de forma assíncrona.

É divertido criar exemplos com o Cuzillion . Por exemplo, esta página possui um script no HEAD, para que a página inteira fique em branco até que o download seja concluído. No entanto, se movermos o script para o final do bloco BODY, o cabeçalho da página será renderizado, pois esses elementos DOM ocorrem acima da tag SCRIPT, como você pode ver nesta página .


10
Honrado Steve bater-me para a resposta, mas vou acrescentar um artigo relevante para o que ele menciona: stevesouders.com/blog/2009/04/27/...
Juan Pablo Buritica

4
veja quais navegadores suportam o asyncatributo, que Steve está recomendando aqui quando diz "ainda melhor carregá-los de forma assíncrona" - stackoverflow.com/questions/1834077/…
Jeff Atwood

Ei, você pode me dizer por que alguém vincularia arquivos CSS a @importdiretivas?
21712 Josh Stodola

6
Qual é a fonte do 2) e, se for verdade, você pode explicar por que uma página termina de carregar o conteúdo e o CSS é aplicado um ou dois segundos depois? (Isso aconteceu, raramente, em minhas próprias páginas onde o CSS estava nas marcas <head>)
Izkata

2
Então devemos colocar jQuery+ jQuery UI+ $(document).ready(function () { });no final da página? Funcionará sempre como esperado?
Olivier Pons

42

Eu não enfatizaria muito os resultados que você obteve, acredito que seja subjetivo, mas tenho um motivo para explicar que é melhor inserir CSS antes de js.

Durante o carregamento do seu site, há dois cenários que você vê:

CASO 1: tela branca> site sem estilo> site com estilo> interação> site com estilo e interativo

CASO 2: tela branca> site sem estilo> interação> site com estilo> site com estilo e interativo


Sinceramente, não consigo imaginar alguém escolhendo o Caso 2. Isso significaria que os visitantes que usam conexões lentas com a Internet se deparam com um site sem estilo, que lhes permite interagir com ele usando Javascript (já que ele já está carregado). Além disso, a quantidade de tempo gasto em um site não estilizado seria maximizada dessa maneira. Por que alguém iria querer isso?

Também funciona melhor como estados jQuery

"Ao usar scripts que dependem do valor das propriedades de estilo CSS, é importante fazer referência a folhas de estilo externas ou incorporar elementos de estilo antes de fazer referência aos scripts".

Quando os arquivos são carregados na ordem errada (primeiro JS e depois CSS), qualquer código Javascript que dependa das propriedades definidas nos arquivos CSS (por exemplo, a largura ou a altura de uma div) não será carregado corretamente. Parece que, com a ordem de carregamento incorreta, as propriedades corretas são 'algumas vezes' conhecidas pelo Javascript (talvez isso seja causado por uma condição de corrida?). Esse efeito parece maior ou menor, dependendo do navegador usado.


2
Como você garantiria que todo o css fosse carregado antes da execução do javascript? Você pode? ou seu javascript deve ser robusto o suficiente para lidar com a situação em que os estilos podem não ser necessariamente carregados.
9136 Jonnio

@ Jonnio Se o seu JS tem uma dependência, você deve explicitar essa dependência. Caso contrário, você sempre terá problemas raros de tempo. Os módulos ES6 são uma boa maneira de fazer isso acontecer, mas há muitas bibliotecas que também podem ser usadas.
Kmkemp 9/11

26

Seus testes foram realizados no seu computador pessoal ou em um servidor da web? É uma página em branco ou é um sistema on-line complexo com imagens, bancos de dados etc.? Seus scripts estão executando uma ação simples de evento flutuante ou são um componente essencial para a renderização e interação do seu site com o usuário? Há várias coisas a considerar aqui, e a relevância dessas recomendações quase sempre se torna regras quando você se aventura no desenvolvimento da Web de alto calibre.

O objetivo da regra "colocar folhas de estilo na parte superior e scripts na parte inferior" é que, em geral, é a melhor maneira de obter uma renderização progressiva ideal , o que é essencial para a experiência do usuário.

Tudo o mais à parte: supondo que seu teste seja válido e você realmente esteja produzindo resultados contrários às regras populares, não seria nenhuma surpresa. Todo site (e tudo o que é necessário para que tudo apareça na tela do usuário) é diferente e a Internet está em constante evolução.


1
Agradeço o argumento que você está expressando em negrito, mas o OP está falando sobre o que acontece quando você varia a ordem com os dois na parte superior, nem na parte inferior.
Nnnnnn

1
Assim, "assumindo que seu teste é válido".
Skippr

21

Eu incluo arquivos CSS antes do Javascript por um motivo diferente.

Se meu Javascript precisar fazer o dimensionamento dinâmico de algum elemento da página (para os casos de canto em que o CSS é realmente principal na parte de trás), carregar o CSS depois que o JS estiver sendo movido pode levar a condições de corrida, onde o elemento é redimensionado antes dos estilos CSS são aplicados e, portanto, parecem estranhos quando os estilos finalmente entram em ação. Se eu carregar o CSS de antemão, posso garantir que as coisas sejam executadas na ordem desejada e que o layout final seja o que eu quero que seja.


2
isso quebrará um dia em algum navegador. Eu não estou adivinhando.
21132 jcolebrand

1
jcolebrand: Sim, acho que não tinha bebido café suficiente quando escrevi isso. (Em retrospecto, eu acho que as coisas importantes são apenas para evitar o carregamento dinâmico de CSS e colocando o JS dentro de um evento domReady se você precisa fazer o dimensionamento dinâmico)
hugomg

Os scripts não devem alterar nenhuma exibição. Esse é o trabalho do CSS. HTML = conteúdo, CSS = Como exibir conteúdo, javascript altera o conteúdo dinamicamente. Além disso, js deve agir somente após (ou enquanto) o DOMContentLoaded é acionado com algumas situações pequenas, mas muito específicas.
Brunoais

@brunoais: Alguns layouts só podem ser criados com Javascript. Por exemplo, qualquer coisa que precise ser redimensionada dinamicamente deve ser feita via Javascript e algumas coisas (como tamanho 100% - 20px) precisam que o Javascript seja feito de maneira portável em navegadores antigos.
hugomg

@missingno Nesses casos, basta usar o evento DOMContentLoaded. Mas eu entendo o que você quer dizer. (Stupid IE!)
brunoais

10

A recomendação para incluir CSS antes do JavaScript é inválida?

Não se você tratá-lo simplesmente como uma recomendação. Mas se você tratá-lo como uma regra rígida e rápida? Sim, é inválido.

De https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded

A folha de estilo carrega a execução do script de bloco, portanto, se você tiver um <script> após, <link rel="stylesheet" ...>a página não concluirá a análise - e o DOMContentLoaded não será acionado - até que a folha de estilo seja carregada.

Parece que você precisa saber do que cada script se baseia e garantir que a execução do script seja adiada até após o evento de conclusão correto. Se o script se basear apenas no DOM, ele poderá continuar em ondomready / domcontentloaded, se depender de imagens a serem carregadas ou folhas de estilo a serem aplicadas, se eu ler a referência acima corretamente, esse código deverá ser adiado até o evento onload.

Eu não acho que um tamanho de meia serve para todos, mesmo que seja assim que eles são vendidos e eu sei que um tamanho de sapato não serve para todos. Eu não acho que exista uma resposta definitiva para carregar primeiro, estilos ou script. É mais uma decisão caso a caso do que deve ser carregado em que ordem e o que pode ser adiado até mais tarde como não estando no "caminho crítico".

Para falar com o observador que comentou que é melhor adiar a capacidade do usuário de interagir até que a folha fique bonita. Existem muitos de vocês por aí e você irrita seus colegas que sentem o contrário. Eles chegaram a um site para atingir um objetivo e os atrasos em sua capacidade de interagir com um site enquanto aguardam por coisas que não importam para terminar o carregamento são muito frustrantes. Não estou dizendo que você está errado, apenas que você deve estar ciente de que existe outra facção que não compartilha sua prioridade.

Esta pergunta se aplica particularmente a todos os anúncios colocados em sites. Eu adoraria que os autores do site processassem apenas divs de espaço reservado para o conteúdo do anúncio e certificassem que o site fosse carregado e interativo antes de injetar os anúncios em um evento onload. Mesmo assim, eu gostaria de ver os anúncios carregados em série, em vez de todos de uma vez, porque eles afetam minha capacidade de rolar o conteúdo do site enquanto os anúncios inchados estão sendo carregados. Mas esse é apenas o ponto de vista de uma pessoa.

  • Conheça seus usuários e o que eles valorizam.
  • Conheça seus usuários e qual ambiente de navegação eles usam.
  • Saiba o que cada arquivo faz e quais são seus pré-requisitos. Fazer tudo funcionar terá precedência sobre velocidade e beleza.
  • Use ferramentas que mostram a linha do tempo da rede durante o desenvolvimento.
  • Teste em cada um dos ambientes que seus usuários usam. Pode ser necessário alterar dinamicamente (lado do servidor, ao criar a página) alterar a ordem de carregamento com base no ambiente do usuário.
  • Em caso de dúvida, altere a ordem e meça novamente.
  • É possível que os estilos e scripts de mistura na ordem de carregamento sejam ótimos; nem todos de um, então todos do outro.
  • Experimente não apenas qual ordem para carregar os arquivos, mas onde. Cabeça? No corpo? Depois do corpo? DOM Pronto / Carregado? Carregado?
  • Considere as opções assíncrona e adiada, quando apropriado, para reduzir o atraso líquido que o usuário experimentará antes de poder interagir com a página. Teste para determinar se eles ajudam ou machucam.
  • Sempre haverá compensações a serem consideradas ao avaliar a ordem de carga ideal. Considerável vs. Responsivo sendo apenas um.

1
O artigo vinculado não reivindica mais "A folha de estilo carrega a execução do script de bloco". Isso não é mais verdade?
Greg

@ Greg - Ainda é verdade. Os scripts precisam consultar os atributos .style do DOM, para que as folhas de estilo ainda bloqueiem a execução do script. Eles podem não bloquear o carregamento do script , se forem inteligentes, mas bloquearão os eventos script.onLoad.
Jimmy Breck-McKye

10

Atualizado 16/12/2017

Eu não tinha certeza sobre os testes no OP. Decidi experimentar um pouco e acabei rebentando alguns dos mitos.

O Synchronous <script src...>bloqueará o download dos recursos abaixo até que seja baixado e executado

Isso não é mais verdade . Dê uma olhada na cascata gerada pelo Chrome 63:

<head>
<script src="//alias-0.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=1"></script>
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=2"></script>
<script src="//alias-2.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=3"></script>
</head>

Inspetor de rede do Chrome -> cascata

<link rel=stylesheet> não bloqueará o download e a execução de scripts abaixo dele

Isto está incorreto . A folha de estilo não vai bloquear download, mas ele irá bloquear a execução do script ( pequena explicação aqui ). Veja o gráfico de desempenho gerado pelo Chrome 63:

<link href="//alias-0.redacted.com/payload.php?type=css&amp;delay=666" rel="stylesheet">
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;block=1000"></script>

Ferramentas de desenvolvimento do Chrome -> desempenho


Tendo em mente o acima exposto, os resultados no OP podem ser explicados da seguinte maneira:

CSS primeiro:

CSS Download  500ms:<------------------------------------------------>
JS Download   400ms:<-------------------------------------->
JS Execution 1000ms:                                                  <-------------------------------------------------------------------------------------------------->
DOM Ready   @1500ms:                                                                                                                                                      

JS Primeiro:

JS Download   400ms:<-------------------------------------->
CSS Download  500ms:<------------------------------------------------>
JS Execution 1000ms:                                        <-------------------------------------------------------------------------------------------------->
DOM Ready   @1400ms:                                                                                                                                            

É também por isso que document.write () é uma das piores idéias já feitas para o HTMLDOM.
Brunoais

1
The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load. javascript.info/… Por que a mesma suposição não se aplica no caso de JS primeiro? Não faz muito sentido para mim, a ordem do JS executado não diz nada sobre seu objetivo.
Thorsten Schöning

4

Não sei exatamente como o seu teste 'renderiza' o tempo que você usa no script java. No entanto, considere isso

Uma página do seu site tem 50k, o que não é razoável. O usuário está na costa leste enquanto o servidor está no oeste. Definitivamente, o MTU não é 10k; portanto, haverá algumas viagens para frente e para trás. Pode demorar 1/2 segundo para receber sua página e folhas de estilo. Normalmente (para mim) javascript (via plugin jquery e outros) são muito mais que CSS. Também existe o que acontece quando a sua conexão à Internet é interrompida no meio da página, mas vamos ignorar isso (acontece ocasionalmente e acredito que o css é processado, mas não tenho 100% de certeza).

Como o css está na cabeça, pode haver conexões adicionais para obtê-lo, o que significa que ele pode terminar potencialmente antes da página. De qualquer forma, durante o tipo que o restante da página leva e nos arquivos javascript (que são muitos mais bytes), a página não tem um estilo, o que torna o site / conexão lento.

MESMO QUE o intérprete JS se recuse a iniciar até que o CSS termine o tempo necessário para baixar o código javascript, especialmente quando o servidor estiver longe do corte em tempo de css, o que fará com que o site não pareça bonito.

É uma pequena otimização, mas essa é a razão.


1
o servidor está na costa leste, fwiw. Aparentemente, você também não tem conhecimento do fato de que agora eles usam uma CDN.
22412 jcolebrand

3

Aqui está um resumo de todas as principais respostas acima (ou talvez abaixo mais tarde :)

Para navegadores modernos, coloque o css onde quiser. Eles analisariam seu arquivo html (que eles chamam de análise especulativa ) e começariam a baixar o css em paralelo com a análise html.

Para navegadores antigos, continue colocando o CSS no topo (se você não quiser mostrar uma página nua, mas interativa primeiro).

Para todos os navegadores, coloque o javascript o mais abaixo possível na página, pois ele interromperá a análise do seu html. De preferência, faça o download de forma assíncrona (ou seja, chamada ajax)

Além disso, existem alguns resultados experimentais para um caso específico que afirma que colocar o javascript em primeiro lugar (em oposição à sabedoria tradicional de colocar o CSS em primeiro lugar) oferece melhor desempenho, mas não há um raciocínio lógico para ele e falta validação quanto à aplicabilidade generalizada, para que você possa ignorá-lo por enquanto.

Então, para responder à pergunta: Sim. A recomendação para incluir o CSS antes do JS é inválida para os navegadores modernos. Coloque o CSS onde quiser e coloque o JS no final, tanto quanto possível.


1

Steve Souders já deu uma resposta definitiva, mas ...

Gostaria de saber se há algum problema com o teste original de Sam e com a repetição de Josh.

Ambos os testes parecem ter sido realizados em conexões de baixa latência, onde a configuração da conexão TCP terá um custo trivial.

Como isso afeta o resultado do teste Eu não tenho certeza e gostaria de ver as cascatas para os testes em uma conexão de latência 'normal', mas ...

O primeiro arquivo baixado deve obter a conexão usada para a página html, e o segundo arquivo baixado obtém a nova conexão. (Liberar o início altera essa dinâmica, mas isso não está sendo feito aqui)

Nos navegadores mais novos, a segunda conexão TCP é aberta especulativamente, de modo que a sobrecarga da conexão é reduzida / desaparece; em navegadores antigos, isso não é verdade e a segunda conexão terá a sobrecarga de ser aberta.

Como / se isso afeta o resultado dos testes, não tenho certeza.


não seguir, a menos que você tem pipelining que é extremamente raro você é muito improvável que se obtenha a configuração da conexão reduzida ... concordam que o teste deve ser repetido em baixa latência
Sam Saffron

Se você olhar para essa cascata, poderá ver onde o Chrome abre especulativamente uma segunda conexão antes que seja necessária webpagetest.org/result/… (o IE9 faz o mesmo) ... Eu estava pensando em latência normal para fins de TCP em vez de baixa - que tipo do ambiente foi realizado o teste?
Andy Davies

2
Re: "Steve Souders já deu uma resposta definitiva, mas ..." A coisa com a evolução da web é que não há respostas definitivas. :) Existem 3-4 maneiras de carregar scripts e as coisas mudam. O real semântica correta deve realmente ter sido para Steve dizer "CSS colocado diante Synchronous JavaScript" Caso contrário, as pessoas errar generalizando como sendo uma regra para todos os scripts ...
hexalys

Sim, mas a maioria das pessoas apenas inclui scripts de forma síncrona, portanto, o conselho de Steve é ​​bom para os não iniciados.
Andy Davies

1

Eu acho que isso não será verdade para todos os casos. Porque o css baixará paralelo, mas o js não pode. Considere para o mesmo caso,

Em vez de ter um css único, pegue 2 ou 3 arquivos css e experimente-os desta maneira,

1) css..css..js 2) css..js..css 3) js..css..css

Tenho certeza que o css..css..js dará um resultado melhor do que todos os outros.


0

Devemos ter em mente que os novos navegadores funcionaram em seus mecanismos Javascript, analisadores e assim por diante, otimizando problemas comuns de código e marcação de uma maneira que os problemas enfrentados em navegadores antigos como <= IE8 não sejam mais relevantes, não apenas com no que diz respeito à marcação, mas também ao uso de variáveis ​​JavaScript, seletores de elementos etc. Posso ver em um futuro não tão distante uma situação em que a tecnologia chegou a um ponto em que o desempenho não é mais um problema.


O desempenho é sempre um problema. Eu quase ignoro que existem navegadores que não seguem as especificações. Acabei de preparar meu código para que os que seguem as especificações funcionem a toda velocidade e os outros, apenas para que funcionem. Então, por exemplo, se funcionar no IE8, tudo bem.
Brunoais

-5

Pessoalmente, eu não daria muita ênfase a essa "sabedoria popular". O que pode ter sido verdade no passado pode muito bem não ser verdade agora. Eu assumiria que todas as operações relacionadas à interpretação e renderização de uma página da Web são totalmente assíncronas ("buscar" algo e "agir sobre ele" são duas coisas totalmente diferentes que podem estar sendo manipuladas por diferentes threads etc. ) e em qualquer caso, completamente fora do seu controle ou da sua preocupação.

Eu colocaria referências CSS na parte "head" do documento, juntamente com quaisquer referências a scripts externos. (Alguns scripts podem exigir que sejam colocados no corpo e, se houver, obrigam.)

Além disso ... se você observar que "isso parece ser mais rápido / mais lento que isso, neste / naquele navegador", trate essa observação como uma curiosidade interessante, mas irrelevante, e não permita que ela influencie suas decisões de design. Muitas coisas mudam rápido demais. (Alguém quer apostar em quantos minutos serão necessários até a equipe do Firefox lançar outro lançamento intermediário de seu produto? Sim, eu também não.)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.