JavaScript Preço 2019

Nos últimos anos, o que é chamado de " preço do JavaScript " sofreu grandes mudanças positivas devido à maior velocidade de análise e compilação de scripts pelo navegador. Agora, em 2019, os principais componentes da carga nos sistemas criados pelo JavaScript são o tempo de carregamento dos scripts e o tempo de execução.



A interação do usuário com o site pode ser interrompida temporariamente se o navegador estiver ocupado executando o código JavaScript. Como resultado, podemos dizer que a otimização de gargalos associados ao carregamento e execução de scripts pode ter um forte impacto positivo no desempenho do site.

Diretrizes práticas gerais para otimização de sites


O que significa acima para desenvolvedores web? O ponto aqui é que o custo dos recursos para analisar (analisar, analisar) e compilar scripts não é tão sério quanto antes. Portanto, ao analisar e otimizar pacotes configuráveis ​​JavaScript, os desenvolvedores devem considerar as três recomendações a seguir:

  1. Tente reduzir o tempo necessário para baixar scripts.

    • Tente manter seus pacotes JS pequenos. Isso é especialmente importante para sites projetados para dispositivos móveis. O uso de pequenos pacotes aprimora o tempo de carregamento do código, reduz o nível de uso da memória e reduz a carga no processador.
    • Tente impedir que todo o código do projeto seja apresentado como um grande pacote. Se o tamanho do pacote exceder aproximadamente 50-100 Kb - divida-o em fragmentos separados de tamanho pequeno. Graças à multiplexação HTTP / 2, várias solicitações de servidor e várias respostas podem ser processadas simultaneamente. Isso reduz a carga no sistema associada à necessidade de atender solicitações adicionais para carregamento de dados.
    • Se você estiver trabalhando em um projeto móvel, tente manter o código o menor possível. Esta recomendação está associada a baixas taxas de dados em redes móveis. Além disso, lute pelo uso econômico da memória.
  2. Tente reduzir o tempo necessário para executar scripts.

    • Evite usar tarefas demoradas que possam carregar o encadeamento principal por um longo tempo e aumentar o tempo necessário para que as páginas estejam em um estado no qual os usuários possam interagir com eles. No ambiente atual, os scripts executados após serem carregados contribuem muito para o "preço do JavaScript".
  3. Não incorpore trechos de código grandes nas páginas.

    • A regra a seguir deve ser respeitada aqui: se o tamanho do script exceder 1 Kb, tente não incorporá-lo no código da página. Um dos motivos desta recomendação é o fato de 1 Kb ser o limite após o qual o cache do código de script externo começa a funcionar no Chrome. Além disso, lembre-se de que a análise e compilação de scripts incorporados ainda estão em execução no encadeamento principal.

Por que é tão importante carregar e executar scripts?


Por que é importante otimizar o tempo de carregamento e execução de scripts em condições modernas? Os tempos de carregamento de script são extremamente importantes em situações em que os sites são acessados ​​através de redes lentas. Apesar de as redes 4G (e até 5G) estarem se espalhando cada vez mais, a propriedade NetworkInformation.effectiveType em muitos casos de uso de conexões móveis à Internet mostra indicadores que estão no nível das redes 3G ou mesmo em níveis mais baixos.

O tempo necessário para executar o código JS é importante para dispositivos móveis com processadores lentos. Devido ao fato de os dispositivos móveis usarem diferentes CPUs e GPUs, devido ao fato de que quando os dispositivos superaquecem, para protegê-los, o desempenho de seus componentes diminui, é possível observar uma lacuna séria entre o desempenho de telefones e tablets caros e baratos. Isso afeta muito o desempenho do código JavaScript, pois a capacidade de executar esse código por um dispositivo é limitada pelos recursos do processador desse dispositivo.

De fato, se analisarmos o tempo total gasto carregando e preparando a página para trabalhar em um navegador como o Chrome, cerca de 30% desse tempo poderá ser gasto executando o código JS. Abaixo está uma análise do carregamento de uma página da Web muito típica (reddit.com) em um computador desktop de alto desempenho.


No processo de carregamento da página, cerca de 10 a 30% do tempo é gasto na execução de código usando V8

Se falamos de dispositivos móveis, em um telefone médio (Moto G4), é necessário 3-4 vezes mais para executar o reddit.com em um código JS do que em um dispositivo de alto nível (Pixel 3). Em um dispositivo fraco (Alcatel 1X custa menos de US $ 100), resolver o mesmo problema requer pelo menos 6 vezes mais tempo do que algo como o Pixel 3.


O tempo necessário para processar o código JS em dispositivos móveis de diferentes classes

Observe que as versões para celular e desktop do reddit.com são diferentes. Portanto, você não pode comparar os resultados de dispositivos móveis e, por exemplo, o MacBook Pro.

Ao tentar otimizar o tempo de execução do código JavaScript, preste atenção às tarefas demoradas que podem capturar o fluxo da interface do usuário por um longo tempo. Essas tarefas podem impedir a execução de outras tarefas extremamente importantes, mesmo quando a aparência da página parece completamente pronta para o trabalho. Tarefas de longo prazo devem ser divididas em tarefas menores. Ao dividir o código em partes e controlar a ordem de carregamento dessas partes, você pode conseguir que as páginas cheguem a um estado interativo mais rapidamente. Esperançosamente, isso fará com que os usuários tenham menos inconveniência na interação com as páginas.


Tarefas de longa execução capturam o encadeamento principal. Eles devem ser quebrados em pedaços

Como as melhorias da V8 aceleram a análise e compilação de scripts?


A velocidade de análise do código JS de origem na V8, desde a época do Chrome 60, aumentou duas vezes. Ao mesmo tempo, a análise e a compilação agora contribuem menos para o "preço do JavaScript". Isso se deve a outros esforços de otimização do Chrome que levam à paralelização dessas tarefas.

Na V8, a quantidade de trabalho em análise e compilação de código produzido no encadeamento principal é reduzida em média em 40%. Por exemplo, para o Facebook, a melhoria desse indicador foi de 46%, para o Pinterest - 62%. O resultado mais alto, 81%, foi obtido no YouTube. Esses resultados são possíveis devido ao fato de a análise e a compilação serem movidas para um fluxo separado. E isso é um complemento às melhorias existentes em relação à solução de streaming das mesmas tarefas fora do fluxo principal.


Tempo de análise de JS em várias versões do Chrome

Você também pode visualizar como as otimizações da V8 produzidas em várias versões do Chrome afetam o tempo do processador necessário para processar o código. Ao mesmo tempo em que o Chrome 61 precisava analisar o código JS do Facebook, o Chrome 75 agora pode analisar o código JS do Facebook e, além disso, analisar o código do Twitter 6 vezes.


No período em que o Chrome 61 precisava processar o código JS do Facebook, o Chrome 75 pode processar o código do Facebook e seis vezes a quantidade de código do Twitter.

Vamos falar sobre como essas melhorias foram alcançadas. Em poucas palavras, os recursos de script podem ser analisados ​​e compilados no modo de fluxo contínuo no fluxo de trabalho. Isso significa o seguinte:

  • O V8 pode analisar e compilar o código JS sem bloquear o encadeamento principal.
  • O processamento de fluxo do script inicia quando o analisador HTML universal encontra a <script> . Um analisador HTML manipula scripts que bloqueiam a análise de página. Encontrando scripts assíncronos, ele continua trabalhando.
  • Na maioria dos cenários do mundo real, caracterizada por determinadas velocidades de conexão de rede, o V8 analisa o código mais rapidamente do que pode carregar. Como resultado, a V8 conclui as tarefas de análise e compilação do código alguns milissegundos após o carregamento dos últimos bytes do script.

Se você falar sobre tudo isso com mais detalhes, o ponto aqui é o seguinte. Em versões muito mais antigas do Chrome, o script precisava ser baixado na íntegra antes de analisá-lo. Essa abordagem é simples e compreensível, mas quando é usada, os recursos do processador são irracionalmente usados. O Chrome, entre as versões 41 e 68, inicia a análise no modo assíncrono, imediatamente após o carregamento do script, executando esta tarefa em um encadeamento separado.


Os scripts são enviados para o navegador em fragmentos. O V8 inicia o processamento de dados de streaming depois de ter pelo menos 30 Kb de código.

No Chrome 71, passamos para um sistema baseado em tarefas. Aqui, o planejador pode iniciar simultaneamente várias sessões de processamento de script assíncrono / atrasado. Devido a essa alteração, a carga criada pela análise do encadeamento principal diminuiu em cerca de 20%. Isso levou a uma melhoria de cerca de 2% nas pontuações TTI / FID obtidas em sites reais.


O Chrome 71 usa um sistema de processamento de código com base em tarefas. Com essa abordagem, o planejador pode processar vários scripts assíncronos / pendentes ao mesmo tempo.

No Chrome 72, tornamos o processamento de streaming a principal maneira de analisar scripts. Agora, mesmo os scripts síncronos regulares são tratados dessa maneira (embora isso não se aplique aos scripts internos). Além disso, paramos de cancelar as operações de análise baseada em tarefas se o encadeamento principal necessitar de código analisado. Isso é feito devido ao fato de que isso leva à necessidade de executar novamente parte do trabalho já realizado.

A versão anterior do Chrome tinha suporte para análise de fluxo e compilação de código. Em seguida, o script baixado da rede deve primeiro entrar no fluxo principal e depois será redirecionado para o sistema de processamento de script de streaming.

Isso geralmente levou o analisador de fluxo a aguardar dados que já foram baixados da rede, mas ainda não foram redirecionados pelo fluxo principal para o processamento do fluxo. Isso aconteceu devido ao fato de que o encadeamento principal pode estar ocupado com outras tarefas (como analisar HTML, criar um layout de página ou executar o código JS).

Agora estamos experimentando como começar a analisar o código ao pré-carregar páginas. Anteriormente, a implementação desse mecanismo era prejudicada pela necessidade de usar os recursos do encadeamento principal para transferir tarefas para o analisador de streaming. Detalhes sobre a análise do código JS executado "instantaneamente" podem ser encontrados aqui .

Como as melhorias afetaram o que pode ser visto nas ferramentas do desenvolvedor?


Além do acima, pode-se notar que havia um problema nas ferramentas do desenvolvedor antes. Consistia no fato de que as informações sobre a tarefa de análise eram exibidas como se elas bloquearem completamente o encadeamento principal. No entanto, o analisador executou operações bloqueando o encadeamento principal apenas quando precisou de novos dados. Desde que passamos do esquema de uso de um único fluxo para processamento de dados de streaming para o esquema no qual as tarefas de processamento de streaming são aplicadas, isso se tornou bastante óbvio. Aqui está o que você pode ver no Chrome 69.


O problema está nas ferramentas do desenvolvedor, devido às quais as informações sobre a análise de scripts foram exibidas como se elas bloquearem completamente o encadeamento principal

Aqui você pode ver que a tarefa de script de análise leva 1,08 segundos. Mas analisar o JavaScript, de fato, não é tão lento! Na maioria das vezes, nada de útil é executado, exceto pela espera de dados do encadeamento principal.
No Chrome 76, você já pode ver uma imagem completamente diferente.


No Chrome 76, a análise é dividida em muitas pequenas tarefas

Em geral, pode-se notar que a guia Desempenho das ferramentas do desenvolvedor é ótima para ver a imagem geral do que está acontecendo na página. Para obter informações mais detalhadas que refletem os recursos da V8, como tempo de análise e tempo de compilação, você pode usar o Rastreamento do Chrome com suporte ao RCS (Runtime Call Stats). Nos dados RCS recebidos, você pode encontrar os indicadores Analisar e Antecedentes e Compilar e Antecedentes. Eles são capazes de relatar quanto tempo levou para analisar e compilar o código JS fora do encadeamento principal. As métricas de análise e compilação indicam quanto tempo foi gasto em atividades relacionadas no encadeamento principal.


Análise de dados RCS usando o Google Tracing

Como as mudanças afetaram o trabalho com sites reais?


Vejamos alguns exemplos de como o processamento de scripts de streaming influenciou a navegação em sites reais.

▍Reddit



Veja reddit.com em um MacBook Pro. Tempo para analisar e compilar o código JS gasto nos encadeamentos principal e de trabalho

Existem vários pacotes JS no site reddit.com, cada um com mais de 100 Kb de tamanho. Eles são agrupados em funções externas, o que leva à execução de grandes volumes de compilação "lenta" no encadeamento principal. Crucial no diagrama acima é o tempo necessário para processar os scripts no encadeamento principal. Isso ocorre porque uma grande carga no encadeamento principal pode aumentar o tempo que leva para a página alternar para o modo interativo. Ao processar o código do site reddit.com, a maior parte do tempo é gasta no encadeamento principal e os recursos do encadeamento de trabalho / plano de fundo são usados ​​no mínimo.

Você pode otimizar este site dividindo alguns pacotes grandes em partes (cerca de 50 Kb cada) e fazendo isso sem envolver o código em uma função. Isso maximizaria o processamento paralelo de scripts. Como resultado, os pacotes podem ser analisados ​​e compilados ao mesmo tempo no modo de streaming. Isso reduziria a carga no encadeamento principal ao preparar a página para o trabalho.

▍Facebook



Veja facebook.com no seu MacBook Pro. Tempo para analisar e compilar o código JS gasto nos encadeamentos principal e de trabalho

Também podemos considerar um site como o facebook.com, que usa cerca de 6 MB de código JS compactado. Esse código é carregado usando aproximadamente 292 solicitações. Alguns deles são assíncronos, outros têm como objetivo pré-carregar dados, outros têm baixa prioridade. A maioria dos scripts do Facebook é pequena em tamanho e foco estreito. Isso pode ter um bom efeito no processamento paralelo de dados por meio de fluxos de segundo plano / trabalho. O fato é que muitos scripts pequenos podem ser analisados ​​e compilados ao mesmo tempo por meio do processamento de scripts de streaming.

Observe que seu site provavelmente é diferente do site do Facebook. Você provavelmente não possui aplicativos mantidos abertos por um longo período de tempo (como o que é um site do Facebook ou a interface do Gmail) e, ao trabalhar com os quais pode ser justificado o download de volumes tão graves de scripts com um navegador de desktop. Mas, apesar disso, podemos dar uma recomendação geral que seja justa para qualquer projeto. Está no fato de que vale a pena dividir o código do aplicativo em pacotes configuráveis ​​modestos e que você precisa fazer o download desses pacotes configuráveis ​​somente quando houver necessidade deles.

Embora a maior parte do trabalho de análise e compilação de código JS possa ser realizada usando ferramentas de streaming em um encadeamento em segundo plano, algumas operações ainda exigem um encadeamento principal. Quando o segmento principal está ocupado com algo, a página não pode responder à interação do usuário. Portanto, é recomendável prestar atenção ao impacto nos sites UX que o carregamento e a execução do código JS têm.

Lembre-se de que nem todos os mecanismos e navegadores JavaScript agora transmitem scripts e otimizam seu carregamento. Apesar disso, esperamos que os princípios gerais de otimização descritos acima possam melhorar a experiência do usuário ao trabalhar com sites visualizados em qualquer um dos navegadores existentes.

Preço de análise JSON


A análise do código JSON pode ser muito mais eficiente do que a análise do código JavaScript. A questão é que a gramática JSON é muito mais simples que a gramática JavaScript. Esse conhecimento pode ser aplicado para melhorar a velocidade de preparação do trabalho de aplicativos da Web que usam grandes objetos de configuração (como repositórios Redux), cuja estrutura se assemelha ao código JSON. Como resultado, verifica-se que, em vez de apresentar os dados como literais de objetos incorporados no código, você pode representá-los como cadeias de objetos JSON e analisar esses objetos em tempo de execução.

A primeira abordagem, usando objetos JS, fica assim:

 const data = { foo: 42, bar: 1337 }; //  

A segunda abordagem, usando cadeias JSON, envolve o uso de tais construções:

 const data = JSON.parse('{"foo":42,"bar":1337}'); //  

Como você só precisa executar o processamento de string JSON uma vez, a abordagem que usa JSON.parse é muito mais rápida do que usar literais de objeto JavaScript. Especialmente - no carregamento de página "frio". É recomendável que você use cadeias JSON para representar objetos que começam em 10 Kb. No entanto, como em qualquer dica de desempenho, essa dica não deve ser seguida sem pensar. Antes de aplicar esta técnica para apresentar dados em produção, é necessário fazer medições e avaliar seu real impacto no projeto.

O uso de literais de objeto como armazenamento para grandes quantidades de dados representa outra ameaça. A questão é que existe o risco de que esses literais possam ser processados ​​duas vezes:

  1. A primeira passagem de processamento é realizada com análise preliminar do literal.
  2. A segunda abordagem é realizada durante a análise "preguiçosa" do literal.

Você não pode se livrar da primeira passagem do processamento de literais de objetos. Felizmente, porém, a segunda passagem pode ser evitada colocando literais de objetos no nível superior ou dentro do PIFE .

E quanto à análise e compilação de códigos em visitas repetidas a sites?


É possível otimizar o desempenho do site para os casos em que os usuários os visitam mais de uma vez, graças aos recursos da V8 para armazenar em cache o código e o bytecode. Quando um script é solicitado pelo servidor pela primeira vez, o Chrome faz o download e passa a V8 para compilação. O navegador, além disso, salva o arquivo desse script em seu cache de disco. Quando a segunda solicitação para baixar o mesmo arquivo JS é executada, o Chrome o pega no cache do navegador e passa novamente a V8 para compilação. Desta vez, no entanto, o código compilado é serializado e anexado ao arquivo de script em cache como metadados.


Sistema de armazenamento em cache de código na V8

Quando o script é solicitado pela terceira vez, o Chrome pega o arquivo e seus metadados do cache e transfere os dois da V8. A V8 desserializa os metadados e, como resultado, pode pular a etapa de compilação. O cache de código é acionado se as visitas ao site forem realizadas dentro de 72 horas. O Chrome também usa a estratégia de armazenamento em cache de código ganancioso quando um trabalhador do serviço é usado para armazenar em cache scripts. Detalhes sobre cache de código podem ser encontrados aqui .

Sumário


Em 2019, os principais gargalos de desempenho das páginas da web são o carregamento e a execução de scripts. Para melhorar a situação, tente usar scripts síncronos (internos) de tamanhos pequenos, necessários para organizar a interação do usuário com a parte da página que lhe é visível imediatamente após o carregamento. Recomenda-se que os scripts usados ​​para atender a outras partes das páginas sejam carregados no modo adiado. Quebrar pacotes grandes em pedaços pequenos. Isso facilitará a implementação de uma estratégia para trabalhar com código, na aplicação em que o código é carregado apenas quando necessário e somente onde é necessário. Isso maximizará os recursos do V8, destinados ao processamento paralelo do código.

Se você estiver desenvolvendo projetos móveis, deve se esforçar para garantir que eles usem o mínimo de código JS possível. Essa recomendação deriva do fato de que os dispositivos móveis geralmente funcionam em redes bastante lentas. Além disso, esses dispositivos podem ser limitados em termos de RAM e recursos de processador disponíveis. Tente encontrar um equilíbrio entre o tempo necessário para preparar scripts baixados da rede e usando o cache. Isso maximizará a quantidade de análise e compilação de código executada fora do encadeamento principal.

Caros leitores! Você otimiza seus projetos da web levando em consideração as peculiaridades do processamento de código JS pelos navegadores modernos?

Source: https://habr.com/ru/post/pt459296/


All Articles