Como e por que criamos insights de performance

No Chrome 102, você verá um novo painel experimental, Insights de desempenho, no DevTools. Nesta postagem, discutiremos não apenas por que estamos trabalhando em um novo painel, mas também os desafios técnicos que nos enfrentou e as decisões que tomamos ao longo do caminho.

ALT_TEXT_HERE

Por que criar outro painel?

Se você ainda não assistiu, postamos um vídeo sobre a criação do painel "Insights de desempenho" e como conseguir insights úteis sobre o desempenho do seu site com ele.

O painel de desempenho atual é um ótimo recurso se você quiser ver todos os dados do seu site em um só lugar, mas achamos que pode ser um pouco complicado. Se você não é especialista em performance, é difícil saber exatamente o que procurar e quais partes da gravação são relevantes.

Entre no Painel Insights, onde você ainda pode visualizar uma linha do tempo do rastro e inspecionar os dados, além de ter uma lista útil do que o DevTools considera os principais "Insights" que valem a pena analisar. Os Insights identificam problemas como solicitações de bloqueio de renderização, mudanças de layout e tarefas longas, por exemplo, que podem afetar de modo negativo o desempenho de carregamento da página do seu site e, especificamente, a pontuação das Core Web Vitals (CWV). Além da sinalização de problemas, os Insights de performance oferecerão sugestões práticas para melhorar sua pontuação nas Core Web Vitals e links para mais recursos e documentação.

Link de feedback no painel

Este painel é experimental, e queremos saber sua opinião. Avise se você encontrar bugs ou solicitar recursos que possam ser úteis para melhorar o desempenho do seu site.

Como criamos insights de desempenho

Assim como o restante do DevTools, criamos insights de desempenho no TypeScript e usamos componentes da Web, com suporte de lit-html, para construir a interface do usuário. O que difere os Insights de performance é que a interface principal da interface é um elemento HTML canvas, e a linha do tempo é mostrada nessa tela. Grande parte da complexidade é motivada pelo gerenciamento dessa tela: não apenas desenhando os detalhes certos no lugar certo, mas também gerenciando eventos do mouse (por exemplo: onde o usuário clicou na tela? eles clicaram em um evento que desenhamos?) e garantiram a rerenderização da tela de forma eficaz.

Várias faixas em uma única tela

Para um determinado site, queremos renderizar várias "faixas", cada uma representando uma categoria diferente de dados. Por exemplo, o painel "Insights" mostra três faixas por padrão:

E à medida que continuarmos a incluir recursos no painel, esperamos adicionar mais faixas.

Nossa ideia inicial era que cada uma dessas faixas renderizasse o próprio <canvas>, para que a visualização principal se tornasse vários elementos de tela empilhados verticalmente. Isso simplificaria a renderização em um nível de faixa, porque cada faixa poderia ser renderizada de forma isolada, e não haveria perigo de renderização de faixas fora dos limites, mas, infelizmente, essa abordagem tem dois problemas principais:

Os elementos canvas são caros para (re)renderizar. Ter várias telas é mais caro do que uma tela, mesmo que essa tela seja maior. A renderização de sobreposições que passam por várias faixas (por exemplo, linhas verticais para marcar eventos como tempo de FCP) se torna complexa: temos que renderizar em várias telas e garantir que todas sejam renderizadas juntas e alinhadas corretamente.

Usar um canvas para toda a interface significou que precisávamos descobrir como garantir que cada faixa fosse renderizada nas coordenadas corretas e não transbordasse para outra faixa. Por exemplo, se uma faixa específica tiver 100 pixels de altura, não podemos permitir que ela renderize algo com 120 pixels de altura e que vague para a faixa abaixo dela. Para resolver isso, podemos usar o clip. Antes de renderizarmos cada faixa, desenhamos um retângulo que representa a janela da faixa visível. Isso garante que todos os caminhos desenhados fora desses limites sejam cortados pela tela.

canvasContext.beginPath();
canvasContext.rect(
    trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();

Também não queríamos que cada faixa soubesse a posição vertical dela. Cada faixa seria renderizada como se estivesse sendo renderizada em (0, 0), e temos um componente de nível mais alto (que chamamos de TrackManager) para gerenciar a posição geral da faixa. Isso pode ser feito com translate, que converte a tela em uma determinada posição (x, y). Exemplo:

canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide

Apesar da configuração do código rect 0, 0 como posição, a translação geral aplicada fará com que o retângulo seja renderizado em 0, 10. Isso nos permite trabalhar com base em faixas, como se estivessem renderizando em (0, 0), e fazer com que nosso gerenciador de faixas faça a tradução conforme ele renderiza cada faixa para garantir que cada faixa seja renderizada corretamente abaixo da anterior.

Telas fora da tela para músicas e destaques

A renderização da tela é relativamente cara, e queremos garantir que o painel "Insights" permaneça estável e responsivo enquanto você trabalha com ele. Às vezes, não é possível evitar a re-renderização de toda a tela: por exemplo, se você alterar o nível de zoom, teremos que começar de novo e renderizar tudo de novo. A nova renderização da tela é particularmente cara, porque não é possível simplesmente renderizar de novo uma pequena parte dela. Você precisa apagar toda a tela e redesenhar. Isso é diferente da rerenderização do DOM, em que as ferramentas podem calcular o trabalho mínimo necessário e não remover tudo e começar de novo.

Uma área em que encontramos problemas visuais foi o destaque. Quando você passa o mouse sobre as métricas no painel, elas são destacadas na linha do tempo. Da mesma forma, se você passa o mouse sobre o Insight de um determinado evento, desenhamos uma borda azul ao redor do evento.

Esse recurso foi implementado pela primeira vez pela detecção de um movimento do mouse sobre um elemento que aciona um destaque e, em seguida, desenhando-o diretamente na tela principal. Nosso problema ocorre quando precisamos remover o destaque: a única opção é redesenhar tudo. É impossível redesenhar a área onde o destaque estava (não sem grandes mudanças na arquitetura), mas reprojetar toda a tela só porque queremos remover uma borda azul ao redor de um item parecia um exagero. Ele também ficava visualmente lento quando você moveu o mouse sobre diferentes itens para acionar vários destaques em rápida sucessão.

Para corrigir isso, dividimos nossa interface em duas telas fora da tela: a tela "principal", em que as faixas são renderizadas, e a tela "destaques", onde os destaques são desenhados. Em seguida, renderizamos copiando essas telas para a única que está visível para o usuário. Podemos usar o método drawImage em um contexto de tela, que pode usar outra tela como origem.

Isso significa que a remoção de um destaque não faz com que a tela principal seja redesenhada. Em vez disso, podemos limpar a tela e copiar a tela principal para a que está visível. Copiar uma tela custa pouco, e o desenho é caro. Por isso, ao mover os destaques para uma tela separada, evitamos esse custo ao ativar e desativar os destaques.

Análise de rastros testada de forma abrangente

Um dos benefícios de criar um novo recurso do zero é que você pode refletir sobre as escolhas técnicas feitas anteriormente e fazer melhorias. Uma das coisas que queríamos melhorar era dividir nosso código explicitamente em duas partes, quase totalmente distintas:

Analisar o arquivo de rastreamento e extrair os dados necessários. Renderizar um conjunto de faixas.

Manter a análise (parte 1) separada do trabalho da interface (parte 2) nos permitiu criar um sistema de análise sólido. Cada trace é executado por uma série de gerenciadores responsáveis por diferentes preocupações: um LayoutShiftHandler calcula todas as informações de que precisamos para as mudanças de layout, e uma NetworkRequestsHandler lida exclusivamente com a extração de solicitações de rede. Essa etapa de análise explícita em que temos diferentes gerenciadores responsáveis por diferentes partes do rastro também é benéfica: a análise de rastros pode ser muito complicada e ajuda a se concentrar em uma preocupação por vez.

Além disso, pudemos testar nossa análise de rastreamento de forma abrangente. Para isso, gravamos gravações no DevTools, salvamos e carregamos essas gravações como parte do nosso pacote de testes. Isso é ótimo porque podemos testar com rastros reais e não criar grandes quantidades de dados de rastros falsos que poderiam se tornar obsoletos.

Teste de captura de tela para interface do Canvas

Ainda no assunto dos testes, geralmente testamos nossos componentes de front-end renderizando-os no navegador e garantindo que eles se comportem como esperado. Podemos enviar eventos de clique para acionar atualizações e confirmar que o DOM gerado pelos componentes está correto. Essa abordagem funciona bem para nós, mas cai quando consideramos a renderização em uma tela. Não há como inspecionar uma tela e determinar o que está desenhado nela. Portanto, nossa abordagem comum de renderização e consulta não é apropriada.

Para aumentar a cobertura, fizemos o teste de capturas de tela. Cada teste aciona uma tela, renderiza a faixa que queremos testar e faz uma captura de tela do elemento da tela. Essa captura de tela é armazenada na nossa base de código para que as execuções de testes futuras comparem a captura de tela armazenada com a que foi gerada. Se as capturas de tela forem diferentes, o teste vai falhar. Também fornecemos uma sinalização para executar o teste e forçar uma atualização de captura de tela quando mudarmos intencionalmente a renderização e precisarmos que o teste seja atualizado.

Os testes de captura de tela não são perfeitos e têm um pouco de corte. Você só pode testar se todo o componente é renderizado como esperado, em vez de fazer declarações mais específicas. Inicialmente, fomos culpados de usá-los em excesso para garantir que cada componente (HTML ou tela) fosse renderizado corretamente. Isso retardou drasticamente nosso conjunto de testes e levou a problemas em que pequenos ajustes na interface do usuário (como mudanças sutis de cor ou adição de alguma margem entre os itens) causavam falha em várias capturas de tela e precisavam ser atualizadas. Agora, reduzimos o uso de capturas de tela e as utilizamos puramente para componentes baseados em tela, e esse equilíbrio tem funcionado bem para nós até agora.

Conclusão

A criação do novo painel de insights de desempenho tem sido uma experiência muito agradável e educativa para a equipe. Aprendemos muito sobre arquivos de rastreamento, como trabalhar com o canvas e muito mais. Esperamos que você goste de usar o novo painel. Mal podemos esperar para saber sua opinião.

Para saber mais sobre o painel "Insights de desempenho", consulte Insights de desempenho: receba insights úteis sobre o desempenho do seu site.

Fazer o download dos canais de visualização

Use o Chrome Canary, Dev ou Beta como seu navegador de desenvolvimento padrão. Esses canais de pré-lançamento oferecem acesso aos recursos mais recentes do DevTools, testam as APIs modernas de plataformas da Web e encontram problemas no site antes dos usuários.

Entrar em contato com a equipe do Chrome DevTools

Use as opções a seguir para discutir os novos recursos e mudanças na publicação ou qualquer outra coisa relacionada ao DevTools.

  • Envie uma sugestão ou feedback em crbug.com.
  • Informe um problema do DevTools em Mais opções   Mais   > Ajuda > Informar problemas no DevTools.
  • Envie um tweet em @ChromeDevTools.
  • Deixe comentários nos nossos vídeos do YouTube sobre a ferramenta DevTools ou nos vídeos do YouTube com dicas sobre o DevTools.