O carregamento de recursos JavaScript grandes causa um impacto significativo na velocidade da página. Divisão seu JavaScript em partes menores e baixando apenas o que é necessário para o funcionamento de uma página durante a inicialização pode melhorar muito o carregamento dela capacidade de resposta, que por sua vez pode melhorar a Interação com o Next da sua página Paint (INP).
Enquanto uma página faz o download, analisa e compila grandes arquivos JavaScript, ela pode se tornar não responde por períodos de tempo. Os elementos da página são visíveis, como são uma parte do HTML inicial de uma página e estilizado por CSS. No entanto, como o JavaScript necessários para alimentar esses elementos interativos, bem como outros scripts carregados por da página, podem estar analisando e executando o JavaScript para que funcionem. A é que o usuário pode sentir que a interação foi significativamente atrasados ou até mesmo corrompidos.
Isso geralmente acontece porque a linha de execução principal está bloqueada enquanto o JavaScript é analisado e compilados na linha de execução principal. Se esse processo demorar muito, o processo interativo os elementos da página podem não responder rápido o suficiente à entrada do usuário. Uma solução para isso é carregar apenas o JavaScript necessário para que a página funcione, enquanto adiar outro JavaScript para carregar mais tarde por meio de uma técnica conhecida como código divisão. O foco deste módulo é a última dessas duas técnicas.
Reduza a análise e a execução do JavaScript durante a inicialização por meio da divisão de código.
O Lighthouse gera um aviso quando a execução do JavaScript demora mais de 2". segundos e falha quando leva mais de 3, 5 segundos. Excesso de JavaScript a análise e a execução são um problema potencial em qualquer ponto da página porque ele pode aumentar o atraso de entrada (link em inglês) de uma interação. se o momento em que o usuário interage com a página coincidir com o momento as principais tarefas da linha de execução responsáveis pelo processamento e execução do JavaScript são em execução.
Além disso, a execução e a análise excessivas de JavaScript são particularmente problemático durante o carregamento inicial da página, pois esse é o ponto na página ciclo de vida que os usuários são muito propensos a interagir com a página. Na verdade, Tempo total de bloqueio (TBT, na sigla em inglês), uma métrica de capacidade de resposta à carga, está altamente correlacionado com INP, sugerindo que os usuários têm uma alta tendência a tentar interações durante o carregamento inicial da página.
A auditoria do Lighthouse que relata o tempo gasto na execução de cada arquivo JavaScript que sua página solicita é útil, pois pode ajudar você a identificar exatamente quais scripts podem ser candidatos à divisão de código. Você pode ir mais longe usando a ferramenta de cobertura no Chrome DevTools para identificar exatamente quais partes o JavaScript de uma página não é utilizado durante o carregamento dela.
A divisão de código é uma técnica útil que pode reduzir o JavaScript inicial de uma página payloads. Ele permite dividir um pacote JavaScript em duas partes:
- O JavaScript é necessário no carregamento da página e, portanto, não pode ser carregado em nenhum outro tempo de resposta.
- JavaScript restante que pode ser carregado posteriormente, com mais frequência no ponto em que o usuário interage com um determinado elemento interativo no da página.
A divisão de código pode ser feita usando a sintaxe dinâmica import()
(link em inglês). Isso
Sintaxe, diferentemente dos elementos <script>
, que solicitam um determinado recurso JavaScript.
durante a inicialização, faz uma solicitação por um recurso JavaScript em um momento posterior do
o ciclo de vida da página.
document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
// Get the form validation named export from the module through destructuring:
const { validateForm } = await import('/validate-form.mjs');
// Validate the form:
validateForm();
}, { once: true });
No snippet JavaScript anterior, o módulo validate-form.mjs
é
transferidos por download, analisados e executados somente quando um usuário desfoca qualquer elemento
<input>
. Nessa situação, o recurso JavaScript responsável
a lógica de validação do formulário só está envolvida na página quando
é mais provável de ser realmente usado.
Bundlers de JavaScript, como webpack, Parcel, Rollup e esbuild, podem ser
configurados para dividir pacotes JavaScript em partes menores
encontrar uma chamada import()
dinâmica no código-fonte. A maioria dessas ferramentas faz
isso automaticamente, mas o esbuild exige que você ative esse recurso
otimização.
Observações úteis sobre a divisão de código
Embora a divisão de código seja um método eficaz para reduzir a contenção da linha de execução principal durante o carregamento inicial da página, vale a pena considerar algumas coisas ao decidir para auditar seu código-fonte JavaScript para identificar oportunidades de divisão de código.
Use um bundler se puder
É uma prática comum que os desenvolvedores usem módulos JavaScript durante a de desenvolvimento de software. É uma excelente melhoria da experiência do desenvolvedor que melhora a legibilidade e a manutenção do código. No entanto, existem algumas características de desempenho abaixo do ideal que podem resultar no envio de JavaScript módulos para produção.
O mais importante é usar um bundler para processar e otimizar sua fonte incluindo os módulos em que você pretende fazer a divisão. Os bundlers são muito eficazes não apenas aplicando otimizações ao código-fonte JavaScript, mas também eficaz para equilibrar questões de desempenho, como tamanho do pacote em relação à taxa de compactação. A eficácia da compressão aumenta com o tamanho do pacote, mas os bundlers também tentam garantir que os pacotes não sejam tão grandes tarefas longas devido à avaliação do script.
Os bundlers também evitam o problema de enviar um grande número de módulos desagrupados
na rede. Arquiteturas que usam módulos JavaScript tendem a ter
árvores de módulos complexas. Quando as árvores de módulos são desagrupadas, cada módulo representa uma
uma solicitação HTTP separada, e a interatividade no seu app da Web poderá sofrer atraso se você
não agrupam módulos. Embora seja possível usar
Dica de recurso <link rel="modulepreload">
(link em inglês) para carregar árvores de módulos grandes logo no início
possível, os pacotes JavaScript ainda são preferíveis em uma performance de carregamento
de negócios.
Não desative acidentalmente a compilação de streaming
O mecanismo JavaScript V8 do Chromium oferece uma série de otimizações prontas para uso para garantir que o código JavaScript de produção seja carregado da maneira mais eficiente possível. Uma dessas otimizações é conhecida como compilação de streaming, análise incremental do HTML transmitido para o navegador—compila blocos transmitidos de JavaScript conforme eles chegam da rede.
Há algumas maneiras de garantir que a compilação de streaming ocorra para seu aplicativo da Web no Chromium:
- Transforme seu código de produção para evitar o uso de módulos JavaScript. Agrupadores pode transformar seu código-fonte JavaScript com base em um destino de compilação e o destino geralmente é específico para um determinado ambiente. O V8 vai aplicar o streaming compilação para qualquer código JavaScript que não use módulos, e é possível configure seu bundler para transformar seu código do módulo JavaScript em uma sintaxe que não usa módulos JavaScript e seus recursos.
- Se você quiser enviar módulos JavaScript para a produção, use o
.mjs
. Independentemente de o JavaScript de produção usar ou não módulos, há Nenhum tipo de conteúdo especial para JavaScript que usa módulos em vez de JavaScript. que não tem. Com relação ao V8, você desativa o streaming Compilação quando você envia módulos JavaScript em produção usando o.js
. . Se você usar a extensão.mjs
para módulos JavaScript, o V8 poderá garantir que a compilação de streaming para código JavaScript com base em módulo não seja de quebrar.
Não deixe que essas considerações impeçam você de usar a divisão de código. Código a divisão é uma maneira eficaz de reduzir os payloads iniciais do JavaScript para os usuários, mas usando um bundler e sabendo como preservar a transmissão do V8 comportamento de compilação, é possível garantir que o código JavaScript de produção seja o mais rápido possível para os usuários.
Demonstração de importação dinâmica
webpack
O webpack vem com um plug-in chamado SplitChunksPlugin
, que permite
configurar como o bundler divide os arquivos JavaScript. O webpack reconhece os dois
instruções import()
dinâmicas e import
estáticas. O comportamento
O SplitChunksPlugin
pode ser modificado especificando a opção chunks
no
configuração:
chunks: async
é o valor padrão e se refere a chamadasimport()
dinâmicas.chunks: initial
refere-se a chamadasimport
estáticas.chunks: all
abrange importações dinâmicasimport()
e estáticas, permitindo que você para compartilhar blocos entre as importaçõesasync
einitial
.
Por padrão, sempre que o webpack encontrar uma instrução import()
dinâmica.
cria um bloco separado para esse módulo:
/* main.js */
// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';
myFunction('Hello world!');
// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
// Assumes top-level await is available. More info:
// https://v8.dev/features/top-level-await
await import('/form-validation.js');
}
A configuração do webpack padrão para o snippet de código anterior resulta em dois blocos separados:
- O bloco
main.js
, que o webpack classifica como um blocoinitial
, que inclui os módulosmain.js
e./my-function.js
. - O bloco
async
, que inclui apenasform-validation.js
(contendo um hash de arquivo no nome do recurso, se configurado). Este bloco só é baixado se e quandocondition
for verdadeira.
Essa configuração permite adiar o carregamento do bloco form-validation.js
até que
quando necessário. Isso pode melhorar a capacidade de resposta de carregamento reduzindo o script
de avaliação durante o carregamento inicial da página. Download e avaliação do script
para o bloco form-validation.js
ocorre quando uma condição especificada é atendida,
Nesse caso, é feito o download do módulo importado dinamicamente. Um exemplo pode ser uma
uma condição em que o download de um polyfill só é feito em um navegador específico, ou — como em
exemplo anterior, o módulo importado é necessário para uma interação do usuário.
Por outro lado, mudar a configuração SplitChunksPlugin
para especificar
O chunks: initial
garante que o código seja dividido apenas nos blocos iniciais. São
blocos, como os importados estaticamente ou listados no entry
do webpack
propriedade. Observando o exemplo anterior, o bloco resultante seria um
combinação de form-validation.js
e main.js
em um único arquivo de script,
resultando em um desempenho potencialmente pior do carregamento da página inicial.
As opções de SplitChunksPlugin
também podem ser configuradas para separar valores maiores
scripts em vários menores, por exemplo, usando a opção maxSize
para instruir o webpack a dividir blocos em arquivos separados se eles excederem o
especificado por maxSize
. Dividir arquivos de script grandes em arquivos menores pode
melhorar a capacidade de resposta da carga, como em alguns casos de avaliação de script com uso intensivo da CPU.
o trabalho é dividido em tarefas menores, que têm menos probabilidade de bloquear as principais
por períodos mais longos.
Além disso, gerar arquivos JavaScript maiores também significa que os scripts são mais chances de invalidação de cache. Por exemplo, se você enviar um script grande com framework e código do aplicativo primário, todo o O pacote pode ser invalidado se apenas o framework for atualizado, mas nada mais o recurso empacotado.
Por outro lado, arquivos de script menores aumentam a probabilidade o visitante recupera recursos do cache, resultando em carregamentos de página mais rápidos no visitas repetidas. No entanto, arquivos menores se beneficiam menos com a compactação do que arquivos maiores e pode aumentar o tempo de retorno da rede em carregamentos de página com uma cache do navegador. É preciso ter cuidado para encontrar o equilíbrio entre o armazenamento em cache da compactação, eficácia da compactação e tempo de avaliação de script.
Demonstração do webpack
Demonstração do SplitChunksPlugin
webpack.
Teste seus conhecimentos
Que tipo de instrução import
é usada ao executar o código
divisão?
import
estático.import()
dinâmico.
Que tipo de instrução import
precisa estar na parte superior.
de um módulo JavaScript e em nenhum outro local?
import
estático.import()
dinâmico.
Ao usar SplitChunksPlugin
no webpack, qual é o
diferença entre um bloco de async
e um
initial
bloco?
async
blocos são carregados usando import()
dinâmico.
e initial
são carregados usando
import
.
async
partes são carregadas usando import
estático.
e initial
são carregados usando
import()
.
A seguir: imagens de carregamento lento e elementos <iframe>
Apesar de ser um tipo de recurso bastante caro, o JavaScript não é
somente o tipo de recurso que você pode adiar o carregamento. Imagem e elementos <iframe>
são recursos potencialmente dispendiosos por si só. Assim como no JavaScript,
pode adiar o carregamento de imagens e elementos <iframe>
com o carregamento lento
elas, que serão explicadas no próximo módulo do curso.