Introduzindo o React Profiler

10 de Setembro de 2018 por Brian Vaughn

React 16.5 adiciona suporte para o novo plugin de profile do DevTools. Este plugin usa a API experimental de profile do React para coletar informações temporais sobre cada componente que é renderizado a fim de identificar gargálos de desempenho em aplicações React. Ele será completamente compatível com nossas futuras funcionalidades de time slicing e suspense.

Este blog post cobre os seguintes tópicos:

Analisando uma aplicação

DevTools irá exibir uma aba chamada “Profiler” para aplicações que suportem a nova API de profiling:

Nova aba

Nota:

react-dom 16.5+ suporta análise no modo DEV. Um pacote de produção para análise está disponível como react-dom/profiling. Leia mais sobre como usar este bundle em fb.me/react-profiling

O painel de “Profiler” estará vazio inicialmente. Clique no botão de gravar para iniciar a análise:

Clique

Uma vez que você começou a gravar, DevTools irá coletar automativamente informações de desempenho cada vez que sua aplicação renderizar. Use sua aplicação como você normalente faria. Quando você finalizar a análise, clique no botão de “Parar”.

Clique

Assumindo que sua aplicação renderizou pelo menos uma vez enquanto a análise acontecia, DevTools irá mostrar diversas formas para ver os dados de desempenho. Iremos olhar cada uma destas formas abaixo.

Lendo dados de desempenho

Navegando por commits

Conceitualmente, React funciona em duas fases:

  • A fase de render determina quais mudanças precisam ser feitas no DOM, por exemplo. Durante esta fase, React executa render e então compara o resultado com o render anterior.
  • A fase de commit aplica todas as mudanças. (No caso do React DOM, é quando o React insere, atualiza e remove nós do DOM.) O React também executa os métodos do ciclo de vida como componentDidMount e componentDidUpdate durante esta fase.

O profiler do DevTools agrupa a informação de desempenho por commit. Commits são exibidos em um gráfico de barra próximo ao topo do profiler:

Gráfico de barras dos commits analisados

Cada barra no gráfico representa um único commit com o commit atualmente selecionado pintado de preto. Você pode clicar numa barra (ou nas setas para esquerda/direita) para selecionar um commit diferente.

A cor e a altura de cada barra corresponde ao tempo que aquele commit demorou para renderizar. (Barras amarelas altas demoraram mais do que as barras azuis menores.)

Filtrando commits

O quanto mais você executar o profile, mais vezes a sua aplicação irá renderizar. Em alguns casos você vai acabar com commits demais para analisar facilmente. O profiler oferece um mecanismo de filtro para ajudar nestes casos. Use-o para especificar um limit e o profiler irá esconder todos os commits que foram mais rápidos que aquele valor.

Filtrando commits por tempo

Gráfico de chama

A visualização de gráfico de chama (flame chart) representa o estado da sua aplicação para um commit particular. Cada barra no gráfico representa um componente React (por exemplo App, Nav). O tamanho e cor da barra representa quanto tempo o componente e seus filhos demoraram para renderizar. (A largura da barra representa quanto tempo foi gasto quando o componente foi renderizado pela última vez e a cor representa quanto tempo foi gasto como parte do commit atual.)

Examplo de gráfico de chama

Nota:

A largura da barra indica quanto tempo demorou para renderizar o componente (e seus filhos) na última vez que foi renderizado. Se o componente não re-renderizou como parte do último commit, o tempo representa uma renderização anterior. O quanto maior for um componente, mais demorado é para ele renderizar.

A cor da barra indica quanto tempo o componente (e seus filhos) demoraram para renderizar no commit selecionado. Componentes amarelos levaram mais tempo, componentes azuis levaram menos tempo e componentes cinza não renderizaram durante este commit.

Por exemplo, o commit acima levou um total de 18.4ms para renderizar. O componente Router foi o “mais caro” para renderizar (levando 18.4ms). A maior parte deste tempo foi devido a seus filhos, Nav (8.4ms) e Route (7.9ms). O resto do tempo se dividiu entre seus filhos remanescentes ou gasto no método de render do próprio componente.

Você pode aumentar ou diminuir o zoom no gráfico de chama clicando nos componentes: Clique em um componente para aumentar ou diminuir o zoom

Clicar num componente irá selecioná-lo e mostrar, no painel lateral direito, informações que incluem suas props e estado no momento deste commit. Você pode analisar e aprender mais sobre como o componente realmente renderizou durante o commit:

Visualizando as props e estado de um componente em um commit

Em alguns casos, selecionar um componente e alternar entre commits pode dar uma dica do porquê o componente renderizou:

Visualizando quais valores mudaram entre commits

A imagem acima mostra que state.scrollOffset mudou entre os commits. Foi isto que provavelmente causou que o componente List renderizasse novamente.

Gráfico de classificação

A visualização de gráfico de classificação (ranked chart) representa um único commit. Cada barra no gráfico representa um componente React (por exemplo App, Nav). O gráfico é ordenado de tal forma que o componente que demorou mais para renderizar fica no topo.

Exemplo de gráfico de classificação

Nota:

O tempo de renderização de um componente inclui o tempo gasto para renderizar seus filhos, portanto, os componentes que demoram mais para renderizar estão geralmente próximos ao topo da árvore.

Assim como no gráfico de chama, você pode aumentar ou diminuir o zoom de um gráfico de classificação ao clicar nos componentes.

Gráfico de componente

Algumas vezes é útil visualizar quantas vezes um componente específico renderizou enquanto você estava analisando. O gráfico de componente fornece esta informação no formato de um gráfico de barras. Cada barra no gráfico representa uma vez que o componente renderizou. A cor e a altura de cada barra corresponde a quanto tempo o componente demorou para renderizar relativamente a outros componentes num commit específico.

Exemplo de gráfico de componente

O gráfico acima mostra que o componente List renderizou 11 vezes. Ele também mostra que cada vez que ele renderizou, foi o componente mais “caro” no commit (significando que foi o mais demorado).

Para visualizar este gráfico, você deve clicar duas vezes num componente ou selecionar um componente e clicar no ícone com um gráfico de barras azul no painel de detalhe a direita. Você pode retornar ao gráfico anterior clicando no botão “x” no painel de detalhe a direita. Você também pode clicar duas vezes numa barra específica para visualizar mais informações sobre aquele commit.

Como visualizar todas as renderizações de um componente específico

Se o componente selecionado não renderizou durante uma sessão de análise, a seguinte mensagem irá ser exibida:

Nenhuma renderização para o componente selecionado

Interações

React recentemente adicionou outra API experimental para rastrear a causa de uma atualização. “Interações” rastreadas com esta API irão ser mostradas no profiler:

O painel de interações

A imagem acima mostra uma sessão de análise que registrou quatro interações. Cada linha representa uma interação que foi rastreada. Os pontos coloridos através da linha representam commits relacionados àquela interação.

Você também pode ver quais interações foram rastreadas para um commit específico a partir das visualizações de gráfico de chama e de gráfico de classificação:

Lista de interações de um commi

Você pode navigar através de interações e commits clicando neles:

Navegue através de interações e commits

A API de rastreamento ainda é novo e iremos abordar ela com mais detalhes em posts futuros.

Guia de soluções de problemas

Nenhum dado de profile foi salvo para a raiz selecionada

Se sua aplicação possui múltiplas “raizes”, você talvez veja a seguinte mensagem após a análise: Nenhum dado foi salvo para a raiz selecionada

Esta mensagem indica que nenhum dado de dessempenho foi gravado para a raiz que está selecionada no painel de “Elementos”. Neste caso, tente selecionar uma raiz diferente no painel para visualizar informações analisadas para aquela raiz:

Selecione uma raiz no painel de "Elements" para visualizar seus dados de desempenho

Nenhum dado de tempo a ser exibido para o commit selecionado

Às vezes, um commit pode ser tão rápido que perfomance.now() não retorna nenhuma informação de tempo significativa para o DevTools. Neste caso, a seguinte mensagem irá aparecer:

Nenhum dado de tempo a ser exibido para o commit selecionado

Vídeo aprofundado

O vídeo a seguir demonstra como o React profiler pode ser usado para detectar e melhorar gargálos de performance numa aplicação React real.