Não combater o scanner de pré-carregamento do navegador

Saiba o que é o scanner de pré-carregamento do navegador, como ele ajuda no desempenho e como você pode evitar que ele atrapalhe.

Um aspecto negligenciado da otimização da Velocidade de página envolve conhecer um pouco sobre os aspectos internos do navegador. Os navegadores fazem algumas otimizações para melhorar o desempenho de maneiras que nós, como desenvolvedores, não podemos. Mas isso só acontece se essas otimizações não forem prejudicadas sem querer.

Uma otimização interna do navegador que é importante entender é o scanner de pré-carregamento do navegador. Nesta postagem, vamos explicar como o scanner de pré-carregamento funciona e, mais importante, como evitar que ele atrapalhe.

O que é um scanner de pré-carga?

Todo navegador tem um analisador HTML principal que tokeniza a marcação bruta e a processa em um modelo de objeto. Isso tudo continua até que o analisador faça uma pausa ao encontrar um recurso de bloqueio, como uma folha de estilo carregada com um elemento <link> ou um script carregado com um elemento <script> sem um atributo async ou defer.

Diagrama do analisador HTML.
Figura 1:um diagrama de como o analisador HTML principal do navegador pode ser bloqueado. Nesse caso, o analisador encontra um elemento <link> para um arquivo CSS externo, o que impede que o navegador analise o restante do documento ou até mesmo renderize qualquer parte dele até que o CSS seja baixado e analisado.

No caso de arquivos CSS, a renderização é bloqueada para evitar um flash de conteúdo sem estilo (FOUC), que ocorre quando uma versão sem estilo de uma página pode ser vista brevemente antes que os estilos sejam aplicados a ela.

A página inicial do web.dev em um estado sem estilo (esquerda) e com estilo (direita).
Figura 2:um exemplo simulado de FOUC. À esquerda, está a página inicial do web.dev sem estilos. À direita, a mesma página com estilos aplicados. O estado sem estilo pode ocorrer em um instante se o navegador não bloquear a renderização enquanto uma folha de estilo está sendo baixada e processada.

O navegador também bloqueia a análise e a renderização da página quando encontra elementos <script> sem um atributo defer ou async.

O motivo é que o navegador não pode saber com certeza se um determinado script vai modificar o DOM enquanto o analisador HTML principal ainda está funcionando. Por isso, é comum carregar o JavaScript no final do documento para que os efeitos do parsing e da renderização bloqueados se tornem marginais.

Esses são bons motivos para o navegador bloquear a análise e a renderização. No entanto, bloquear qualquer uma dessas etapas importantes é indesejável, já que elas podem atrasar o show ao adiar a descoberta de outros recursos importantes. Felizmente, os navegadores fazem o possível para reduzir esses problemas usando um analisador HTML secundário chamado scanner de pré-carregamento.

Um diagrama do analisador HTML principal (à esquerda) e do scanner de pré-carregamento (à direita), que é o analisador HTML secundário.
Figura 3:um diagrama que mostra como o scanner de pré-carregamento funciona em paralelo com o analisador HTML principal para carregar recursos de forma especulativa. Aqui, o analisador HTML principal é bloqueado ao carregar e processar o CSS antes de começar a processar a marcação de imagem no elemento <body>. No entanto, o scanner de pré-carregamento pode analisar a marcação bruta para encontrar esse recurso de imagem e começar a carregá-lo antes que o analisador HTML principal seja desbloqueado.

A função de um scanner de pré-carregamento é especulativa, ou seja, ele examina a marcação bruta para encontrar recursos a serem buscados de forma oportunista antes que o analisador HTML principal os descubra.

Como saber quando o scanner de pré-carregamento está funcionando

O scanner de pré-carregamento existe porque a renderização e a análise foram bloqueadas. Se esses dois problemas de desempenho nunca tivessem existido, o scanner de pré-carregamento não seria muito útil. A chave para descobrir se uma página da Web se beneficia do scanner de pré-carregamento depende desses fenômenos de bloqueio. Para isso, introduza um atraso artificial nas solicitações e descubra onde o scanner de pré-carregamento está funcionando.

Confira esta página de texto e imagens básicos com uma folha de estilo como exemplo. Como os arquivos CSS bloqueiam a renderização e a análise, você introduz um atraso artificial de dois segundos para a folha de estilo por um serviço de proxy. Esse atraso facilita a visualização na cascata de rede de onde o scanner de pré-carregamento está funcionando.

O gráfico de cascata de rede do WebPageTest ilustra um atraso artificial de dois segundos imposto à folha de estilo.
Figura 4:um gráfico em cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. Mesmo que a folha de estilo seja atrasada artificialmente por um proxy em dois segundos antes de começar a carregar, a imagem localizada mais tarde na carga útil de marcação é descoberta pelo scanner de pré-carregamento.

Como você pode ver na cascata, o scanner de pré-carregamento descobre o elemento <img> mesmo quando a renderização e a análise de documentos estão bloqueadas. Sem essa otimização, o navegador não pode buscar itens de forma oportunista durante o período de bloqueio, e mais solicitações de recursos seriam consecutivas em vez de simultâneas.

Agora que já vimos esse exemplo simples, vamos analisar alguns padrões do mundo real em que o scanner de pré-carregamento pode ser derrotado e o que pode ser feito para corrigir isso.

Scripts async injetados

Digamos que você tenha HTML no seu <head> que inclui JavaScript inline, como este:

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

Os scripts injetados são async por padrão. Portanto, quando esse script é injetado, ele se comporta como se o atributo async tivesse sido aplicado a ele. Isso significa que ele será executado assim que possível e não vai bloquear a renderização. Parece ótimo, não é? No entanto, se você presumir que esse <script> inline vem depois de um elemento <link> que carrega um arquivo CSS externo, o resultado será abaixo do ideal:

Este gráfico do WebPageTest mostra a verificação de pré-carregamento sendo derrotada quando um script é injetado.
Fig. 5:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. A página contém uma única folha de estilo e um script async injetado. O scanner de pré-carregamento não consegue descobrir o script durante a fase de bloqueio de renderização porque ele é injetado no cliente.

Vamos detalhar o que aconteceu:

  1. Em 0 segundos, o documento principal é solicitado.
  2. Em 1,4 segundo, o primeiro byte da solicitação de navegação chega.
  3. Após 2 segundos, o CSS e a imagem são solicitados.
  4. Como o analisador é bloqueado ao carregar a folha de estilo e o JavaScript inline que injeta o script async vem depois dessa folha de estilo em 2,6 segundos, a funcionalidade fornecida por esse script não fica disponível assim que poderia.

Isso não é ideal porque a solicitação do script só ocorre depois que o download da folha de estilo é concluído. Isso atrasa a execução do script o mais rápido possível. Por outro lado, como o elemento <img> pode ser descoberto na marcação fornecida pelo servidor, ele é descoberto pelo scanner de pré-carregamento.

Então, o que acontece se você usar uma tag <script> normal com o atributo async em vez de injetar o script no DOM?

<script src="/yall.min.js" async></script>

Este é o resultado:

Um diagrama em cascata de rede do WebPageTest mostrando como um script assíncrono carregado usando o elemento de script HTML ainda pode ser descoberto pelo scanner de pré-carregamento do navegador, mesmo que o analisador HTML principal do navegador esteja bloqueado durante o download e o processamento de uma folha de estilo.
Figura 6:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. A página contém uma única folha de estilo e um único elemento async <script>. O scanner de pré-carregamento descobre o script durante a fase de bloqueio de renderização e o carrega simultaneamente com o CSS.

Pode haver uma tentação de sugerir que esses problemas podem ser resolvidos usando rel=preload. Isso certamente funcionaria, mas pode ter alguns efeitos colaterais. Afinal, por que usar rel=preload para corrigir um problema que pode ser evitado não injetando um elemento <script> no DOM?

Um diagrama em cascata do WebPageTest mostrando como a dica de recurso rel=preload é usada para promover a descoberta de um script injetado de forma assíncrona, embora de uma maneira que possa ter efeitos colaterais não intencionais.
Fig. 7:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. A página contém uma única folha de estilo e um script async injetado, mas o script async é pré-carregado para garantir que seja descoberto antes.

A pré-carga "corrige" o problema aqui, mas introduz um novo problema: o script async nas duas primeiras demonstrações, apesar de ser carregado no <head>, é carregado com prioridade "Baixa", enquanto a folha de estilo é carregada com prioridade "Máxima". Na última demonstração, em que o script async é pré-carregado, a folha de estilo ainda é carregada com prioridade "Highest", mas a prioridade do script foi promovida para "High".

Quando a prioridade de um recurso é aumentada, o navegador aloca mais largura de banda para ele. Isso significa que, mesmo que a folha de estilo tenha a prioridade mais alta, a prioridade aumentada do script pode causar disputa de largura de banda. Isso pode ser um fator em conexões lentas ou em casos em que os recursos são muito grandes.

A resposta aqui é simples: se um script for necessário durante a inicialização, não prejudique o scanner de pré-carregamento injetando-o no DOM. Faça experimentos conforme necessário com o posicionamento do elemento <script>, bem como com atributos como defer e async.

Carregamento lento com JavaScript

O carregamento lento é um ótimo método para conservar dados, geralmente aplicado a imagens. No entanto, às vezes, o carregamento lento é aplicado incorretamente a imagens que estão "acima da dobra", por assim dizer.

Isso apresenta possíveis problemas com a capacidade de descoberta de recursos no que diz respeito ao scanner de pré-carregamento e pode atrasar desnecessariamente o tempo necessário para descobrir, baixar, decodificar e apresentar uma referência a uma imagem. Vamos pegar esta marcação de imagem como exemplo:

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

O uso de um prefixo data- é um padrão comum em carregadores lentos com tecnologia JavaScript. Quando a imagem é rolada para dentro da janela de visualização, o carregador lento remove o prefixo data-. Isso significa que, no exemplo anterior, data-src se torna src. Essa atualização solicita que o navegador busque o recurso.

Esse padrão não é problemático até ser aplicado a imagens que estão na janela de visualização durante a inicialização. Como o scanner de pré-carregamento não lê o atributo data-src da mesma forma que um atributo src (ou srcset), a referência da imagem não é descoberta antes. Pior ainda, o carregamento da imagem é atrasado até depois que o JavaScript do carregador lento é baixado, compilado e executado.

Um gráfico de cascata de rede do WebPageTest mostrando como uma imagem carregada de forma lenta que está na janela de visualização durante a inicialização é necessariamente atrasada porque o scanner de pré-carregamento do navegador não consegue encontrar o recurso de imagem e só é carregada quando o JavaScript necessário para o carregamento lento funcionar é carregado. A imagem é descoberta muito depois do que deveria.
Figura 8:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O recurso de imagem é carregado de forma desnecessária, mesmo que esteja visível na janela de visualização durante a inicialização. Isso prejudica o scanner de pré-carregamento e causa um atraso desnecessário.

Dependendo do tamanho da imagem, que pode variar de acordo com o tamanho da janela de visualização, ela pode ser um elemento candidato para a Largest Contentful Paint (LCP). Quando o scanner de pré-carregamento não consegue buscar especulativamente o recurso de imagem com antecedência, possivelmente durante o ponto em que as folhas de estilo da página bloqueiam a renderização, a LCP é afetada.

A solução é mudar a marcação da imagem:

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

Esse é o padrão ideal para imagens que estão na janela de visualização durante a inicialização, já que o scanner de pré-carregamento vai descobrir e buscar o recurso de imagem mais rapidamente.

Um gráfico em cascata de rede do WebPageTest mostrando um cenário de carregamento de uma imagem na janela de visualização durante a inicialização. A imagem não é carregada de forma lenta, o que significa que ela não depende do script para ser carregada. Assim, o scanner de pré-carregamento pode descobri-la mais cedo.
Fig. 9:um gráfico em cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O scanner de pré-carregamento descobre o recurso de imagem antes do início do carregamento de CSS e JavaScript, o que dá ao navegador uma vantagem inicial no carregamento.

O resultado neste exemplo simplificado é uma melhoria de 100 milissegundos no LCP em uma conexão lenta. Pode não parecer uma grande melhoria, mas é quando você considera que a solução é uma correção rápida de marcação e que a maioria das páginas da Web é mais complexa do que este conjunto de exemplos. Isso significa que os candidatos a LCP podem ter que disputar a largura de banda com muitos outros recursos, então otimizações como essa se tornam cada vez mais importantes.

Imagens de plano de fundo do CSS

O scanner de pré-carregamento do navegador verifica a marcação. Ele não verifica outros tipos de recursos, como CSS, que podem envolver buscas de imagens referenciadas pela propriedade background-image.

Assim como o HTML, os navegadores processam o CSS em um modelo de objeto próprio, conhecido como CSSOM. Se recursos externos forem descobertos à medida que o CSSOM é construído, eles serão solicitados no momento da descoberta, e não pelo scanner de pré-carregamento.

Digamos que o candidato a LCP da sua página seja um elemento com uma propriedade CSS background-image. Veja a seguir o que acontece quando os recursos são carregados:

Um gráfico de cascata de rede do WebPageTest mostrando uma página com um candidato a LCP carregado do CSS usando a propriedade background-image. Como a imagem candidata ao LCP está em um tipo de recurso que o scanner de pré-carregamento do navegador não pode examinar, o carregamento do recurso é adiado até que o CSS seja baixado e processado, atrasando o tempo de renderização do candidato ao LCP.
Figura 10:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O candidato a LCP da página é um elemento com uma propriedade CSS background-image (linha 3). A imagem solicitada não começa a ser buscada até que o analisador CSS a encontre.

Nesse caso, o scanner de pré-carregamento não é tanto derrotado, mas sim não envolvido. Mesmo assim, se um candidato a LCP na página for de uma propriedade CSS background-image, pré-carregue essa imagem:

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

Essa dica rel=preload é pequena, mas ajuda o navegador a descobrir a imagem mais cedo do que faria de outra forma:

Um gráfico em cascata de rede do WebPageTest mostrando uma imagem de plano de fundo CSS (que é a candidata a LCP) carregando muito antes devido ao uso de uma dica rel=preload. O tempo de LCP melhora em aproximadamente 250 milissegundos.
Fig. 11:um gráfico em cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O candidato a LCP da página é um elemento com uma propriedade CSS background-image (linha 3). A dica rel=preload ajuda o navegador a descobrir a imagem cerca de 250 milissegundos antes do que sem a dica.

Com a dica rel=preload, o candidato a LCP é descoberto mais cedo, reduzindo o tempo de LCP. Embora essa dica ajude a corrigir o problema, a melhor opção pode ser avaliar se o candidato a LCP da imagem precisa ser carregado do CSS. Com uma tag <img>, você tem mais controle sobre o carregamento de uma imagem adequada para a janela de visualização, permitindo que o scanner de pré-carregamento a descubra.

Inlining de muitos recursos

O inlining é uma prática que coloca um recurso dentro do HTML. É possível inserir folhas de estilo em elementos <style>, scripts em elementos <script> e praticamente qualquer outro recurso usando a codificação base64.

A incorporação de recursos pode ser mais rápida do que o download porque não é emitida uma solicitação separada para o recurso. Ele está no documento e carrega instantaneamente. No entanto, há desvantagens significativas:

  • Se você não estiver armazenando em cache seu HTML (o que é impossível se a resposta HTML for dinâmica), os recursos inline nunca serão armazenados em cache. Isso afeta a performance porque os recursos inline não são reutilizáveis.
  • Mesmo que seja possível armazenar HTML em cache, os recursos inline não são compartilhados entre documentos. Isso reduz a eficiência do armazenamento em cache em comparação com arquivos externos que podem ser armazenados em cache e reutilizados em toda uma origem.
  • Se você fizer isso em excesso, vai atrasar a descoberta de recursos mais adiante no documento pelo scanner de pré-carregamento, porque o download desse conteúdo extra em linha leva mais tempo.

Confira esta página como exemplo. Em determinadas condições, o candidato a LCP é a imagem na parte de cima da página, e o CSS está em um arquivo separado carregado por um elemento <link>. A página também usa quatro fontes da Web, que são solicitadas como arquivos separados do recurso CSS.

Um gráfico de cascata de rede do WebPageTest de uma página com um arquivo CSS externo com quatro fontes referenciadas. A imagem candidata a LCP é descoberta pelo scanner de pré-carregamento no devido tempo.
Fig. 12:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O candidato a LCP da página é uma imagem carregada de um elemento <img>, mas é descoberto pelo scanner de pré-carregamento porque o CSS e as fontes necessárias para o carregamento de página estão em recursos separados, o que não atrasa o trabalho do scanner.

O que acontece se o CSS e todas as fontes forem in-line como recursos base64?

Um gráfico de cascata de rede do WebPageTest de uma página com um arquivo CSS externo com quatro fontes referenciadas. O scanner de pré-carregamento atrasa significativamente a descoberta da imagem LCP .
Figura 13:um gráfico de cascata de rede do WebPageTest de uma página da Web executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. O candidato a LCP da página é uma imagem carregada de um elemento <img>, mas a inclusão do CSS e dos quatro recursos de fonte no `` atrasa a descoberta da imagem pelo scanner de pré-carregamento até que esses recursos sejam totalmente baixados.

O impacto da inclusão inline gera consequências negativas para o LCP neste exemplo e para a performance em geral. A versão da página que não incorpora nada renderiza a imagem LCP em cerca de 3,5 segundos. A página que inlina tudo não renderiza a imagem LCP até pouco mais de 7 segundos.

Há mais em jogo aqui do que apenas o scanner de pré-carregamento. A incorporação de fontes não é uma boa estratégia porque o base64 é um formato ineficiente para recursos binários. Outro fator é que os recursos de fontes externas não são baixados, a menos que sejam considerados necessários pelo CSSOM. Quando essas fontes são incorporadas como base64, elas são baixadas, sejam necessárias para a página atual ou não.

Uma pré-carga poderia melhorar as coisas aqui? Claro. Você pode pré-carregar a imagem LCP e reduzir o tempo de LCP, mas o aumento do HTML potencialmente não armazenável em cache com recursos in-line tem outras consequências negativas no desempenho. A First Contentful Paint (FCP) também é afetada por esse padrão. Na versão da página em que nada está inlined, a FCP é de aproximadamente 2,7 segundos. Na versão em que tudo está inlinado, o FCP é de aproximadamente 5,8 segundos.

Tenha muito cuidado ao inserir elementos no HTML, especialmente recursos codificados em base64. Em geral, isso não é recomendado, exceto para recursos muito pequenos. Faça o mínimo possível de inlining, porque fazer demais é arriscado.

Renderização de marcação com JavaScript do lado do cliente

Não há dúvidas: o JavaScript afeta a Velocidade de página. Os desenvolvedores não só dependem dele para oferecer interatividade, mas também há uma tendência de confiar nele para entregar o próprio conteúdo. Isso melhora a experiência do desenvolvedor de algumas maneiras, mas os benefícios para os desenvolvedores nem sempre se traduzem em benefícios para os usuários.

Um padrão que pode prejudicar o scanner de pré-carregamento é a renderização de marcação com JavaScript do lado do cliente:

Um diagrama de cascata de rede do WebPageTest mostrando uma página básica com imagens e texto renderizados completamente no cliente em JavaScript. Como a marcação está contida em JavaScript, o scanner de pré-carregamento não consegue detectar nenhum dos recursos. Todos os recursos também são atrasados devido ao tempo extra de rede e processamento exigido pelos frameworks JavaScript.
Figura 14:um gráfico de cascata de rede do WebPageTest de uma página da Web renderizada pelo cliente executada no Chrome em um dispositivo móvel com uma conexão 3G simulada. Como o conteúdo está em JavaScript e depende de uma estrutura para renderizar, o recurso de imagem na marcação renderizada pelo cliente fica oculto do scanner de pré-carregamento. A experiência equivalente renderizada no servidor é mostrada na Figura 9.

Quando os payloads de marcação são contidos e renderizados inteiramente pelo JavaScript no navegador, todos os recursos nessa marcação ficam invisíveis para o scanner de pré-carregamento. Isso atrasa a descoberta de recursos importantes, o que certamente afeta o LCP. Nesses exemplos, a solicitação da imagem LCP é significativamente atrasada em comparação com a experiência equivalente renderizada pelo servidor que não exige JavaScript para aparecer.

Isso se desvia um pouco do foco deste artigo, mas os efeitos da renderização de marcação no cliente vão muito além de derrotar o scanner de pré-carregamento. Por exemplo, introduzir JavaScript para oferecer uma experiência que não exige isso aumenta o tempo de processamento desnecessário, o que pode afetar a Interaction to Next Paint (INP). Renderizar quantidades extremamente grandes de marcação no cliente tem mais chances de gerar tarefas longas do que a mesma quantidade de marcação enviada pelo servidor. O motivo disso, além do processamento extra que o JavaScript envolve, é que os navegadores transmitem a marcação do servidor e dividem a renderização de forma a limitar tarefas longas. Por outro lado, a marcação renderizada do lado do cliente é processada como uma única tarefa monolítica, o que pode afetar o INP de uma página.

A solução para esse cenário depende da resposta a esta pergunta: Há um motivo para a marcação da sua página não ser fornecida pelo servidor, em vez de ser renderizada no cliente? Se a resposta for "não", considere a renderização do lado do servidor (SSR, na sigla em inglês) ou a marcação gerada estaticamente sempre que possível. Isso vai ajudar o scanner de pré-carregamento a descobrir e buscar recursos importantes de forma oportunista com antecedência.

Se a sua página precisar de JavaScript para anexar funcionalidades a algumas partes da marcação, você ainda poderá fazer isso com SSR, usando JavaScript simples ou hidratação para aproveitar o melhor dos dois mundos.

Ajude o scanner de pré-carregamento

O scanner de pré-carregamento é uma otimização de navegador altamente eficaz que ajuda as páginas a carregar mais rápido durante a inicialização. Ao evitar padrões que prejudicam a capacidade de descobrir recursos importantes com antecedência, você não está apenas simplificando o desenvolvimento para si mesmo, mas também criando experiências melhores para os usuários que vão gerar resultados melhores em muitas métricas, incluindo algumas Core Web Vitals.

Para recapitular, confira os principais pontos deste post:

  • O scanner de pré-carregamento do navegador é um analisador HTML secundário que faz a verificação antes do principal se ele estiver bloqueado para descobrir recursos que podem ser buscados antes.
  • Recursos que não estão presentes na marcação fornecida pelo servidor na solicitação de navegação inicial não podem ser descobertos pelo scanner de pré-carregamento. Algumas maneiras de burlar o scanner de pré-carregamento incluem, entre outras:
    • Injetar recursos no DOM com JavaScript, sejam scripts, imagens, folhas de estilo ou qualquer outra coisa que seria melhor no payload de marcação inicial do servidor.
    • Carregamento lento de imagens ou iframes acima da dobra usando uma solução JavaScript.
    • Renderização de marcação no cliente que pode conter referências a sub-recursos de documentos usando JavaScript.
  • O scanner de pré-carregamento só verifica HTML. Ele não examina o conteúdo de outros recursos, principalmente CSS, que podem incluir referências a recursos importantes, incluindo candidatos a LCP.

Se, por qualquer motivo, você não conseguir evitar um padrão que afete negativamente a capacidade do scanner de pré-carregamento de acelerar o desempenho do carregamento, considere a dica de recurso rel=preload. Se você usar, teste em ferramentas de laboratório para garantir que esteja produzindo o efeito desejado. Por fim, não faça pré-carregamento de muitos recursos, porque, quando você prioriza tudo, nada é priorizado.

Recursos

Imagem principal do Unsplash, de Mohammad Rahmani .