Otimizar o carregamento de recursos

No módulo anterior, alguma teoria por trás do caminho crítico de renderização era e como os recursos bloqueadores de renderização e de análise podem atrasar um a renderização inicial da página. Agora que você entende um pouco da teoria por trás você já pode aprender algumas técnicas para otimizar os recursos caminho de renderização.

Conforme uma página é carregada, muitos recursos são referenciados no HTML, que fornecem uma página com sua aparência e layout através de CSS, bem como sua interatividade por meio de JavaScript. Neste módulo, vamos abordar vários conceitos importantes relacionados esses recursos e como eles afetam o tempo de carregamento da página são abordados.

Bloqueio de renderização

Como discutimos no módulo anterior, o CSS é um recurso de render-blocking, já que impede que o navegador renderize conteúdo até que o modelo de objetos CSS (CSSOM). O navegador bloqueia a renderização para evitar que um Flash de Conteúdo sem estilo (FOUC, na sigla em inglês), que não é desejável do ponto de vista da experiência do usuário.

No vídeo anterior, há um breve FOUC em que você pode ver a página sem qualquer estilo. Posteriormente, todos os estilos serão aplicados assim que o CSS da página carregado da rede, e a versão sem estilo da página está imediatamente substituída pela versão estilizada.

De modo geral, um FOUC não é comum, mas o conceito é importante entender para que você saiba por que o navegador bloqueia a renderização da página até que o CSS seja baixado e aplicado à página. Bloqueio de renderização não é necessariamente indesejável, mas você quer minimizar a duração dela em manter seu CSS otimizado.

Bloqueio do analisador

Um recurso que bloqueia o analisador interrompe o analisador HTML, como um <script> sem os atributos async ou defer. Quando o analisador encontra um <script>, o navegador precisa avaliar e executar o script antes de prosseguir com a análise do restante do HTML. Isso ocorre por padrão, pois os scripts podem modificar ou acessar o DOM durante um período enquanto ele ainda está sendo construído.

<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>

Ao usar arquivos JavaScript externos (sem async ou defer), o analisador é bloqueada desde quando o arquivo é descoberto até que ele seja baixado, analisado e executada. Ao usar JavaScript inline, o analisador é bloqueado de forma semelhante até o script in-line é analisado e executado.

O leitor de pré-carregamento

A verificação de pré-carregamento é uma otimização do navegador na forma de um HTML secundário que analisa a resposta HTML bruta para localizar e buscar, de forma especulativa, recursos antes que o analisador HTML primário os descubra. Para exemplo, o scanner de pré-carregamento permitiria ao navegador iniciar o download de um recurso especificado em um elemento <img>, mesmo quando o analisador HTML está bloqueado ao buscar e processar recursos como CSS e JavaScript.

Recursos essenciais devem ser incluídos para usar a verificação de pré-carregamento na marcação HTML enviada pelo servidor. Os seguintes padrões de carregamento de recursos são detectável pelo verificador de pré-carregamento:

  • Imagens carregadas pelo CSS usando a propriedade background-image. Essas imagens referências estão em CSS e não podem ser descobertas pelo scanner de pré-carregamento.
  • Scripts carregados dinamicamente na forma da marcação de elemento <script> injetada no DOM usando JavaScript ou módulos carregados usando import() dinâmica.
  • HTML renderizado no cliente usando JavaScript. Essa marcação está contida em strings em recursos JavaScript e não é detectável pelo pré-carregamento de leitura.
  • Declarações @import de CSS.

Todos esses padrões de carregamento de recursos são descobertos tardiamente e, portanto, não se beneficiem do scanner de pré-carregamento. Evite-os sempre que possível. Se evitar esses padrões não é possível. No entanto, você pode usar uma Dica preload para evitar atrasos na descoberta de recursos.

CSS

O CSS determina a apresentação e o layout de uma página. Conforme descrito anteriormente, o CSS é um recurso bloqueador de renderização. Otimizar o CSS pode ter um impacto o impacto no tempo total de carregamento da página.

Minificação

Reduzir arquivos CSS reduz o tamanho do arquivo de um recurso CSS, tornando-os mais rápidos para fazer o download. Isso é conseguido principalmente pela remoção de conteúdo de um arquivo CSS de origem, como espaços e outros caracteres invisíveis, e a saída o resultado para um arquivo recém-otimizado:

/* Unminified CSS: */

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

Em sua forma mais básica, a minificação de CSS é uma otimização eficaz que pode melhorar a FCP do site e, quem sabe, a LCP em alguns casos. Ferramentas como bundlers podem realizar automaticamente essa otimização para você na produção builds.

Remover CSS não usado

Antes de renderizar qualquer conteúdo, o navegador precisa fazer o download e analisar todos folhas de estilo. O tempo necessário para concluir a análise também inclui estilos que não são usados na página atual. Se você estiver usando um bundler que combina todos os CSSs recursos em um único arquivo, é provável que os usuários façam o download de mais CSS do que necessárias para renderizar a página atual.

Para descobrir um CSS não usado na página atual, use a ferramenta de cobertura no Chrome. do DevTools.

Uma captura de tela da ferramenta de cobertura no Chrome DevTools. Um arquivo CSS está selecionado no painel inferior, mostrando uma quantidade considerável de CSS não utilizada pelo layout da página atual.
A ferramenta de cobertura do Chrome DevTools é útil para detectar CSS (e JavaScript) não utilizados pela página atual. Ele pode ser usado para dividir arquivos CSS em vários recursos para serem carregados por páginas diferentes, em vez de o envio de um pacote de CSS muito maior que pode atrasar a renderização da página.

A remoção de CSS não utilizado tem dois efeitos: além de reduzir o download tempo, você está otimizando a construção da árvore de renderização, já que o navegador precisa processar menos regras CSS.

Evitar declarações @import de CSS

Embora possa parecer conveniente, evite declarações @import no CSS:

/* Don't do this: */
@import url('style.css');

Da mesma forma que o elemento <link> funciona em HTML, a declaração @import no CSS permite importar um recurso CSS externo de uma folha de estilo. A a principal diferença entre essas duas abordagens é que o elemento HTML <link> faz parte da resposta HTML e, portanto, foi descoberto muito antes arquivo transferido por download por uma declaração @import.

Isso acontece porque, para que uma declaração @import seja descoberto, é necessário primeiro fazer o download do arquivo CSS que o contém. Isso resulta no conhecido como cadeia de solicitações que, no caso do CSS, causará atrasos. quanto tempo leva para uma página ser renderizada inicialmente. Outra desvantagem é que as folhas de estilo carregadas usando uma declaração @import não podem ser descobertas pelo o scanner de pré-carregamento e, portanto, se tornam recursos de bloqueio de renderização descobertos tardiamente.

<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">

Na maioria dos casos, é possível substituir o @import usando uma <link rel="stylesheet">. Os elementos <link> permitem que as folhas de estilo sejam transferidos simultaneamente e reduz o tempo total de carregamento, em oposição ao @import que fazem o download das folhas de estilo consecutivamente.

CSS essencial inline

O tempo necessário para fazer o download dos arquivos CSS pode aumentar a FCP da página. In-line estilos importantes no documento <head> elimina a solicitação de rede para uma recurso CSS e, quando feito corretamente, pode melhorar os tempos de carregamento iniciais quando uma o cache do navegador do usuário não está preparado. O CSS restante pode ser carregado de forma assíncrona ou anexada ao final do elemento <body>.

<head>
  <title>Page Title</title>
  <!-- ... -->
  <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
  <!-- Other page markup... -->
  <link rel="stylesheet" href="non-critical.css">
</body>

Como desvantagem, colocar uma grande quantidade de CSS em linha adiciona mais bytes ao arquivo Resposta HTML. Como os recursos HTML muitas vezes não podem ser armazenados em cache por muito tempo — ou tudo. Isso significa que o CSS embutido não é armazenado em cache para páginas subsequentes que possam usar o mesmo CSS em folhas de estilo externas. Teste e avalie o desempenho desempenho para garantir que compensações valem o esforço.

Demonstrações de CSS

JavaScript

O JavaScript gera a maior parte da interatividade na Web, mas isso tem um custo. Enviar muito JavaScript pode fazer com que sua página da Web demore para responder durante carregamento e pode até causar problemas de capacidade de resposta que atrasam as interações, o que pode ser frustrante para os usuários.

JavaScript bloqueador de renderização

Ao carregar elementos <script> sem os atributos defer ou async, os o navegador bloqueia a análise e a renderização até que o script seja baixado, analisado e executada. Da mesma forma, os scripts inline bloqueiam o analisador até que o script seja analisado e executados.

async x defer

async e defer permitem que scripts externos sejam carregados sem bloquear o HTML. analisador enquanto os scripts (incluindo scripts inline) com type="module" estão adiado automaticamente. No entanto, async e defer têm algumas diferenças que é importante de entender.

Representação de vários mecanismos de carregamento de script, todos detalhando os papéis de analisador, busca e execução com base em vários atributos usados, como async, defer, type=&#39;module&#39; e uma combinação dos três.
Fonte: https://html.spec.whatwg.org/multipage/scripting.html (link em inglês)

Os scripts carregados com async são analisados e executados imediatamente após o download. enquanto os scripts carregados com defer são executados quando a análise do documento HTML é concluído, isso ocorre ao mesmo tempo que o evento DOMContentLoaded do navegador. Além disso, os scripts async podem ser executados fora de ordem, enquanto os scripts defer são executadas na ordem em que aparecem na marcação.

Renderização do cliente

De modo geral, evite usar JavaScript para renderizar conteúdos críticos ou elemento da LCP da página. Isso é conhecido como renderização pelo cliente e é uma técnica muito usada em aplicativos de página única (SPAs).

A marcação renderizada pelo JavaScript evita o verificador de pré-carregamento, enquanto os recursos contidas na marcação renderizada pelo cliente não são detectáveis por ela. Isso atrasar o download de recursos cruciais, como uma imagem da LCP. O navegador só começa a fazer o download da imagem da LCP depois que o script é executado e adicionado o elemento ao DOM. Por sua vez, o script só pode ser executado depois de descobertos, baixados e analisados. Isso é conhecido como solicitação crítica em cadeia e precisam ser evitados.

Além disso, a renderização da marcação usando JavaScript tem maior probabilidade de gerar tarefas longas do que a marcação baixada do servidor em resposta a uma solicitação de navegação solicitação. O uso extensivo da renderização de HTML pelo cliente pode afetar negativamente latência de interação. Isso é especialmente verdadeiro nos casos em que o DOM de uma página é muito grande, o que aciona um trabalho de renderização significativo quando o JavaScript modifica ao DOM.

Minificação

Semelhante ao CSS, a redução de JavaScript reduz o tamanho do arquivo do recurso de script. Isso pode levar a downloads mais rápidos, permitindo que o navegador vá para a de análise e compilação de JavaScript mais rapidamente.

Além disso, a minificação de JavaScript vai um passo além da minificação. outros recursos, como CSS. Quando o JavaScript é reduzido, ele não é apenas removido como espaços, tabulações e comentários, mas símbolos na fonte JavaScript são encurtadas. Esse processo é conhecido como uglificação. Para para ver a diferença, use o seguinte código-fonte JavaScript:

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}

Quando o código-fonte JavaScript anterior for uglificado, o resultado poderá parecer parecido com este snippet de código:

// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

No snippet anterior, é possível ver que a variável legível scriptElement na origem é encurtado para t. Quando aplicada em uma grande de scripts, as economias podem ser consideráveis, sem afetar recursos que o JavaScript de produção de um site fornece.

Se você estiver usando um bundler para processar o código-fonte de seu site, a uglificação isso geralmente é feito de modo automático em builds de produção. Upentes, como Terser, por exemplo, também são altamente configuráveis, o que permite ajustar o agressividade do algoritmo de uglificação para conseguir o máximo de economia. No entanto, os padrões de qualquer ferramenta de unificação geralmente são suficientes para causar o equilíbrio certo entre tamanho da saída e preservação de recursos.

Demonstrações de JavaScript

Teste seus conhecimentos

Qual é a melhor forma de carregar vários arquivos CSS no navegador?

A declaração CSS @import.
Vários elementos <link>.

O que o verificador de pré-carregamento do navegador faz?

Detecta elementos <link rel="preload"> em um recurso HTML.
É um analisador HTML secundário que examina a marcação bruta para descobrir recursos antes que o analisador do DOM possa descobri-los mais rapidamente.

Por que o navegador bloqueia temporariamente a análise de HTML por padrão quando fazer o download de recursos JavaScript?

Como a avaliação do JavaScript é uma tarefa que consome muita CPU, e pausar A análise HTML dá mais largura de banda à CPU para concluir o carregamento de scripts.
Porque os scripts podem modificar ou acessar o DOM.
Para evitar uma exibição de conteúdo não estilizado (FOUC, na sigla em inglês).

A seguir: como ajudar o navegador com dicas de recursos

Agora que você sabe como os recursos carregados no elemento <head> podem afetar o carregamento inicial da página e várias métricas, é hora de prosseguir. Nos próximos exploramos as dicas de recursos e como elas dão dicas valiosas para no navegador para começar a carregar recursos e abrir conexões para servidores antes do que o navegador faria sem eles.