Como e por que criamos insights de performance

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

ALT_TEXT_HERE

Por que criar outro painel?

Se você ainda não viu, postamos um vídeo sobre por que criar o painel "Insights de performance" e como receber insights úteis sobre a performance do seu site com ele.

O painel de performance atual é um ótimo recurso se você quiser ver todos os dados do seu site em um só lugar, mas achamos que ele pode ser um pouco confuso. 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 ver uma linha do tempo do seu rastreamento e inspecionar os dados, mas também receber uma lista útil do que o DevTools considera os principais "Insights" que valem a pena investigar. Os insights identificam problemas como solicitações de bloqueio de renderização, mudanças de layout e tarefas longas, entre outros, que podem afetar negativamente a performance de carregamento da página do seu site e, especificamente, as pontuações das Core Web Vitals (CWV). Além de sinalizar problemas, o Performance Insights oferece sugestões práticas para melhorar suas pontuações de CWV e links para mais recursos e documentação.

Link de feedback no painel

Esse painel é experimental e queremos saber sua opinião! Entre em contato se encontrar bugs ou tiver solicitações de recursos que possam ajudar você a melhorar o desempenho do seu site.

Como criamos os Insights de performance

Assim como o restante do DevTools, criamos o Performance Insights em TypeScript e usamos componentes da Web, com suporte de lit-html, para criar a interface do usuário. A diferença é que a interface principal do Performance Insights é um elemento HTML canvas, e a linha do tempo é desenhada nesse canvas. Grande parte da complexidade vem do gerenciamento dessa tela: não apenas desenhar os detalhes certos no lugar certo, mas também gerenciar eventos do mouse (por exemplo, onde o usuário clicou na tela? Eles clicaram em um evento que desenhamos?) e garantir que vamos renderizar a tela de maneira eficaz.

Várias faixas em uma única tela

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

E, conforme adicionamos recursos ao painel, esperamos que mais músicas sejam incluídas.

Inicialmente, pensamos que cada uma dessas faixas renderizaria seu próprio <canvas>, para que a visualização principal se tornasse vários elementos de tela empilhados verticalmente. Isso simplificaria a renderização no nível da faixa, porque cada faixa poderia ser renderizada isoladamente, sem o risco de uma faixa ser renderizada fora dos limites. No entanto, essa abordagem tem dois problemas principais:

Os elementos canvas são caros para renderizar (novamente). Ter várias telas é mais caro do que uma, mesmo que ela seja maior. Renderizar sobreposições que abrangem várias faixas (por exemplo, linhas verticais para marcar eventos como o tempo do FCP) se torna complexo: precisamos renderizar em várias telas e garantir que todas sejam renderizadas juntas e alinhadas corretamente.

Usar um canvas para toda a interface significava que precisávamos descobrir como garantir que cada faixa fosse renderizada nas coordenadas certas e não transbordasse para outra faixa. Por exemplo, se uma faixa específica tiver 100 px de altura, não podemos permitir que ela renderize algo com 120 px de altura e invada a faixa abaixo dela. Para resolver isso, podemos usar clip. Antes de renderizar cada faixa, desenhamos um retângulo que representa a janela de 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 precisasse saber sua posição vertical: cada faixa deveria se renderizar como se estivesse sendo renderizada em (0, 0), e temos um componente de nível superior (que chamamos de TrackManager) para gerenciar a posição geral da faixa. Isso pode ser feito com translate, que traduz a tela por 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 de o código rect definir 0, 0 como a posição, a tradução geral aplicada fará com que o retângulo seja renderizado em 0, 10. Isso nos permite trabalhar com base em faixas como se estivéssemos renderizando em (0, 0), e fazer com que nosso gerenciador de faixas traduza à medida que renderiza cada faixa para garantir que cada uma seja renderizada corretamente abaixo da anterior.

Telas fora da tela para faixas e destaques

A renderização do Canvas é relativamente cara, e queremos garantir que o painel Insights permaneça suave e responsivo enquanto você trabalha com ele. Às vezes, não é possível evitar a nova renderização de toda a tela. Por exemplo, se você mudar o nível de zoom, é necessário começar de novo e renderizar tudo. A nova renderização do canvas é particularmente cara porque não é possível renderizar apenas uma pequena parte dele. É necessário limpar todo o canvas e redesenhar. Isso é diferente da renderização do DOM, em que as ferramentas podem calcular o trabalho mínimo necessário e não remover tudo para começar de novo.

Um problema visual que encontramos foi o destaque. Quando você passa o cursor sobre as métricas no painel, elas são destacadas na linha do tempo. Da mesma forma, se você passa o cursor sobre um insight de um determinado evento, uma borda azul é desenhada ao redor dele.

Esse recurso foi implementado primeiro detectando um movimento do mouse sobre um elemento que aciona um destaque e, em seguida, desenhando esse destaque diretamente na tela principal. O problema surge quando temos que remover o destaque: a única opção é redesenhar tudo. É impossível apenas redesenhar a área em que o destaque estava (sem grandes mudanças arquitetônicas), mas redesenhar toda a tela só porque queremos remover uma borda azul ao redor de um item pareceu exagerado. Também havia um atraso visual se você movia rapidamente 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", onde as faixas são renderizadas, e a tela "destaques", onde os destaques são desenhados. Em seguida, renderizamos copiando essas telas para a única tela 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 remover 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 tela visível. Copiar uma tela é barato, mas desenhar é caro. Ao mover os destaques para uma tela separada, evitamos esse custo ao ativar e desativar os destaques.

Análise de rastreamento 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 explicitamente nosso código em duas partes quase totalmente distintas:

Analise o arquivo de rastreamento e extraia os dados necessários. Renderizar um conjunto de faixas.

Manter a análise (parte 1) separada do trabalho de UI (parte 2) nos permitiu criar um sistema de análise sólido. Cada rastreamento é executado por uma série de Handlers, que são responsáveis por diferentes questões: um LayoutShiftHandler calcula todas as informações necessárias para mudanças de layout, e um NetworkRequestsHandler lida exclusivamente com a extração de solicitações de rede. Ter essa etapa de análise explícita, em que temos diferentes manipuladores responsáveis por diferentes partes do rastreamento, também foi benéfico: a análise de rastreamento pode ficar muito complicada, e é útil poder se concentrar em uma questão por vez.

Também conseguimos testar de forma abrangente a análise de rastreamento gravando no DevTools, salvando e carregando como parte do nosso conjunto de testes. Isso é ótimo porque podemos testar com rastreamentos reais e não criar grandes quantidades de dados de rastreamento falsos que podem ficar obsoletos.

Teste de captura de tela para interface do usuário do canvas

Ainda sobre 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 afirmar que o DOM gerado pelos componentes está correto. Essa abordagem funciona bem para nós, mas não é adequada para renderizar em uma tela. Não há como inspecionar uma tela e determinar o que está desenhado nela. Portanto, nossa abordagem usual de renderização e consulta não é adequada.

Para ter alguma cobertura de teste, recorremos ao teste de captura de tela. Cada teste inicia uma tela, renderiza a faixa que queremos testar e faz uma captura de tela do elemento de tela. Essa captura de tela é armazenada na nossa base de código, e as execuções de teste futuras vão comparar a captura armazenada com a que elas geram. Se as capturas de tela forem diferentes, o teste vai falhar. Também fornecemos uma flag para executar o teste e forçar uma atualização de captura de tela quando mudamos propositalmente a renderização e precisamos que o teste seja atualizado.

Os testes de captura de tela não são perfeitos e são um pouco diretos. Você só pode testar se o componente inteiro é renderizado conforme o esperado, em vez de asserções mais específicas. Inicialmente, abusamos deles para garantir que cada componente (HTML ou canvas) fosse renderizado corretamente. Isso diminuiu drasticamente nossa suíte de testes e causou problemas em que pequenos ajustes quase irrelevantes na interface (como mudanças sutis de cor ou adição de margem entre itens) faziam com que várias capturas de tela falhassem e precisassem ser atualizadas. Agora reduzimos o uso de capturas de tela e as usamos apenas para componentes baseados em tela. Esse equilíbrio tem funcionado bem para nós até agora.

Conclusão

Criar o novo painel de insights de performance foi uma experiência muito agradável e educativa para a equipe. Aprendemos muito sobre arquivos de rastreamento, como trabalhar com telas e muito mais. Esperamos que você goste de usar o novo painel e aguardamos seu feedback.

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

Baixar os canais de visualização

Use o Chrome Canary, Dev ou Beta como navegador de desenvolvimento padrão. Esses canais de prévia oferecem acesso aos recursos mais recentes do DevTools, permitem testar APIs de plataforma da Web de ponta e ajudam a encontrar problemas no seu site antes que os usuários o façam.

Entre em contato com a equipe do Chrome DevTools

Use as opções a seguir para discutir os novos recursos, atualizações ou qualquer outra coisa relacionada ao DevTools.