À medida que criamos sites mais dependentes de JavaScript, às vezes pagamos pelo que enviamos de maneiras que nem sempre conseguimos ver com facilidade. Neste artigo, abordaremos por que um pouco de disciplina pode ajudar se você quiser que seu site carregue e seja interativo rapidamente em dispositivos móveis. Enviar menos JavaScript pode significar menos tempo na transmissão de rede, menos tempo gasto com descompactação de código e menos tempo para analisar e compilar esse JavaScript.
Rede
Quando a maioria dos desenvolvedores pensa no custo do JavaScript, é em termos de custo de download e execução. Quanto mais lenta é a conexão de um usuário, quanto mais lenta é a conexão de um usuário, mais bytes de JavaScript pela rede são enviados.
Isso pode ser um problema, já que o tipo de conexão de rede eficaz que um usuário tem pode não ser 3G, 4G ou Wi-Fi. Você pode estar usando o Wi-Fi de uma cafeteria, mas conectado a um ponto de acesso de rede móvel com velocidades de 2G.
É possível reduzir o custo de transferência de rede do JavaScript usando:
- Envie apenas o código que o usuário precisa.
- Use a divisão de código para dividir o JavaScript no que é crítico e no que não é. Os bundlers de módulos, como o webpack, oferecem suporte à divisão de código.
- Carregar lentamente códigos não críticos.
- Minimização
- Use UglifyJS para reduzir o código do ES5.
- Use babel-minify ou uglify-es para reduzir o ES2015+.
- Compactação
- No mínimo, use o gzip para compactar recursos baseados em texto.
- Considere usar o Brotli aproximadamente q11 (links em inglês). O Brotli tem um desempenho melhor que o gzip na taxa de compactação. Isso ajudou a CertSimple a economizar 17% no tamanho de bytes JS compactados e o LinkedIn a economizar 4% nos tempos de carregamento.
- Como remover códigos não utilizados
- Identifique oportunidades de código que podem ser removidos ou carregados lentamente com a cobertura de código do DevTools.
- Use o babel-preset-env e a lista de navegadores para evitar a transcompilação de recursos que já estão em navegadores mais recentes. Para desenvolvedores avançados, a análise cuidadosa dos pacotes de webpack pode ser útil para identificar oportunidades de cortar dependências desnecessárias.
- Para remover o código, consulte tree-shaking, as otimizações avançadas do closure Compiler e os plug-ins de corte de biblioteca, como lodash-babel-plugin ou ContextReplacementPlugin do webpack para bibliotecas como Moment.js.
- Como armazenar o código em cache para minimizar as viagens de rede.
- Use o armazenamento em cache HTTP para garantir que os navegadores armazenem as respostas em cache de maneira eficaz. Determine os tempos de vida ideais para scripts (max-age) e forneça tokens de validação (ETag) para evitar a transferência de bytes inalterados.
- O armazenamento em cache do Service Worker pode tornar a rede do app resiliente e oferecer acesso antecipado a recursos como o cache de código do V8.
- Use o armazenamento em cache de longo prazo para não precisar buscar novamente recursos que não foram alterados. Se estiver usando o Webpack, consulte hash do nome de arquivo (link em inglês).
Analisar/compilar
Após o download, um dos custos mais pesados do JavaScript é o momento em que um mecanismo de JS analisa/compila esse código. No Chrome DevTools, a análise e a compilação fazem parte do tempo de "Script" amarelo no painel "Desempenho".
As guias Bottom-Up e Call Tree mostram os tempos exatos de análise/compilação:
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-cfd35a90562dd.png?authuser=6&hl=pt)
Mas, por que isso é importante?
Passar muito tempo analisando/compilando um código pode atrasar muito a rapidez com que um usuário pode interagir com o site. Quanto mais JavaScript você enviar, mais tempo levará para analisá-lo e compilá-lo antes que seu site fique interativo.
Byte por byte, o JavaScript é mais caro para o navegador processar do que uma imagem ou fonte da Web de tamanho equivalente — Tom Dale
Em comparação com o JavaScript, há vários custos envolvidos no processamento de imagens de tamanhos equivalentes (elas ainda precisam ser decodificadas). No entanto, em hardwares de dispositivos móveis comuns, é mais provável que o JS afete negativamente a interatividade de uma página.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-e3dc86ddc7603.png?authuser=6&hl=pt)
Quando falamos sobre a lentidão da análise e compilação, porque o contexto é importante, estamos nos referindo à média de smartphones. Os usuários médios podem ter smartphones com CPUs e GPUs lentas, sem cache L2/L3 e com limitações de memória.
Os recursos de rede e do dispositivo nem sempre correspondem. Um usuário com uma conexão Fiber incrível não tem necessariamente a melhor CPU para analisar e avaliar o JavaScript enviado ao dispositivo. Isso também é verdade, mas uma conexão de rede terrível, mas uma CPU ultrarrápida. — Kristofer Baxter, LinkedIn
Confira abaixo o custo de analisar aproximadamente 1 MB de JavaScript descompactado (simples) em hardware de baixa e alta tecnologia. Há uma diferença de 2 a 5 vezes no tempo para analisar/compilar código entre os smartphones mais rápidos do mercado e os smartphones comuns.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-52af247f207f5.png?authuser=6&hl=pt)
Que tal um site real, como o CNN.com?
No iPhone 8 de última geração, leva apenas cerca de 4 segundos para analisar/compilar o JS da CNN, em comparação com aproximadamente 13 segundos em um smartphone médio (Moto G4). Isso pode afetar significativamente a rapidez com que um usuário pode interagir completamente com o site.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-7cafa788a7bdf.png?authuser=6&hl=pt)
Isso destaca a importância de testar em um hardware médio (como o Moto G4) em vez de testar apenas o smartphone que pode estar no seu bolso. No entanto, o contexto é importante: otimize para as condições do dispositivo e da rede dos seus usuários.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-6de3a79335e9b.png?authuser=6&hl=pt)
Estamos realmente enviando muito JavaScript? É possível :)
Usando o HTTP Archive (aproximadamente 500 mil sites) para analisar o estado do JavaScript em dispositivos móveis, podemos ver que 50% dos sites levam mais de 14 segundos para se tornarem interativos. Esses sites gastam até 4 segundos apenas analisando e compilando JS.
Considere o tempo necessário para buscar e processar o JS e outros recursos, e talvez não seja surpreendente que os usuários precisem esperar um pouco antes de sentir que as páginas estão prontas para uso. Com certeza podemos fazer melhor.
A remoção de JavaScript não essencial das suas páginas pode reduzir os tempos de transmissão, a análise e a compilação que usam muita CPU, além da possível sobrecarga da memória. Isso também ajuda a acelerar a interatividade das suas páginas.
Ambiente de execução
Não é apenas analisar e compilar que pode ter custos. A execução de JavaScript (executando o código depois de analisado/compilado) é uma das operações que precisa acontecer na linha de execução principal. Tempos de execução longos também podem adiar a rapidez com que um usuário pode interagir com seu site.
Se o script for executado por mais de 50 ms, o tempo até a interação será atrasado por todo o tempo necessário para fazer o download, compilar e executar o JS – Alex Russell
Para resolver isso, o JavaScript tem a vantagem de estar em pequenos pedaços para evitar o bloqueio da linha de execução principal. Descubra se é possível reduzir a quantidade de trabalho realizada durante a execução.
Outros custos
O JavaScript pode afetar o desempenho da página de outras maneiras:
- Memória. As páginas podem parecer instáveis ou pausar com frequência devido à coleta de lixo (GC, na sigla em inglês). Quando um navegador recupera a memória, a execução do JS é pausada para que um navegador que coleta lixo com frequência possa pausar a execução com uma frequência maior do que a esperada. Evite vazamentos de memória e pausas frequentes de GCs para manter as páginas livres de instabilidade.
- Durante o tempo de execução, o JavaScript de longa duração pode bloquear a linha de execução principal, causando
páginas que não respondem. Dividir o trabalho em partes menores (usando
requestAnimationFrame()
ourequestIdleCallback()
para a programação) pode minimizar problemas de capacidade de resposta, o que pode ajudar a melhorar a Interação com a próxima exibição (INP, na sigla em inglês).
Padrões para reduzir o custo de entrega de JavaScript
Quando você está tentando manter os tempos de análise/compilação e transmissão de rede para JavaScript lentos, há padrões que podem ajudar, como o agrupamento com base em rota ou o PRPL (link em inglês).
PRPL (em inglês)
PRPL (Push, Render, Pre-cache, Lazy-load) é um padrão que otimiza a interatividade por meio de armazenamento em cache e divisão de código agressivos:
Vamos conferir seu impacto.
Analisamos o tempo de carregamento de sites para dispositivos móveis populares e Progressive Web Apps usando as Estatísticas de chamada do tempo de execução do V8. Como podemos ver, o tempo de análise (mostrado em laranja) é uma parte significativa do tempo gasto por muitos desses sites:
O Wego, um site que usa PRPL, consegue manter um tempo de análise baixo para suas rotas, ficando interativo muito rapidamente. Muitos dos outros sites acima adotaram a divisão de código e os orçamentos de desempenho para tentar reduzir os custos com JS.
Bootstrap progressivo
Muitos sites otimizam a visibilidade do conteúdo em detrimento da interatividade. Para ter uma primeira exibição rápida quando há grandes pacotes JavaScript, os desenvolvedores às vezes empregam a renderização no servidor. Em seguida, fazem "upgrade" para anexar gerenciadores de eventos quando o JavaScript finalmente é buscado.
Tenha cuidado, porque isso tem seus próprios custos. Você 1) geralmente envia uma resposta HTML maior, que pode impulsionar nossa interatividade, 2) pode deixar o usuário em um vale estranho onde metade da experiência não pode ser interativa até que o JavaScript termine o processamento.
O bootstrap progressivo pode ser uma abordagem melhor. Envie uma página minimamente funcional, composta apenas pelo HTML/JS/CSS necessário para a rota atual. Conforme mais recursos chegam, o app pode carregar lentamente e desbloquear mais funcionalidades.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-bc9d1b36573cd.png?authuser=6&hl=pt)
Carregar o código proporcionalmente ao que está sendo visualizado é o segredo. PRPL e bootstrap progressivo são padrões que podem ajudar a fazer isso.
Conclusões
O tamanho da transmissão é fundamental para redes de baixa capacidade. O tempo de análise é importante para dispositivos vinculados à CPU. É importante mantê-los baixos.
Equipes tiveram sucesso na adoção de orçamentos de desempenho rigorosos para manter os tempos de transmissão e análise/compilação de JavaScript baixos. Confira "Can You Afford It?: reais de desempenho da Web" e orientações sobre orçamentos para dispositivos móveis.
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/optimizing-content-efficiency-javascript-startup-optimization/image/alttexthere-72d5f9f9722e.png?authuser=6&hl=pt)
Se você estiver criando um site destinado a dispositivos móveis, faça seu melhor para desenvolver em hardware representativo, mantenha os tempos de análise/compilação do JavaScript baixos e adote um orçamento de desempenho para garantir que sua equipe possa acompanhar os custos de JavaScript.
Saiba mais
- Chrome Dev Summit 2017: práticas recomendadas de carregamento moderno
- Desempenho de inicialização em JavaScript
- Solucionando a crise de desempenho na Web — Nolan Lawson
- Você tem esse custo? Orçamentos de performance real — Alex Russell
- Como avaliar frameworks e bibliotecas da Web — Kristofer Baxter
- Resultados do Cloudflare ao testar o Brotli para compactação. Observe que o Brotli dinâmico com qualidade mais alta pode atrasar a renderização inicial da página. Por isso, avalie com cuidado. Recomendamos compactar estaticamente.
- Performance Futures — Sam Saccone