- Fundamentos: O que é Performance e por que Importa
- Core Web Vitals: LCP, INP e CLS na Prática
- Entrega & Rendering: CDN, Lazy Loading e Estratégias de Render
- JavaScript: Seu Bundle Está Pesado Demais
- CSS: Critical Path e Layout Thrashing
- DevTools: Explorando a Performance no Navegador
- Monitoramento: Medindo o que Importa em Produção
Conhecer as métricas é metade do trabalho. A outra metade é saber onde olhar quando algo está lento. O Chrome DevTools é o instrumento mais completo para isso — mas tem tantos painéis e opções que é fácil se perder.
Painéis de Performance
Grava tudo no main thread durante um período. Flame graph, long tasks, frames, timings de métricas. O mais poderoso para debugging de runtime.
Waterfall de todos os recursos: quando cada um foi solicitado, fases (DNS, TCP, TTFB, download), prioridades, tamanhos.
Heap snapshots para encontrar memory leaks. Compare snapshots antes e depois de uma ação para ver o que cresceu.
Mostra qual % do JS e CSS baixado é realmente executado. Mapa do tesouro para code splitting.
Auditoria completa com scores, oportunidades e diagnósticos. Integrado ao DevTools, acessível via aba Lighthouse.
Painel mais novo (Chrome 102+) que identifica CWV e long tasks automaticamente com sugestões contextuais.
Configuração antes de medir
- Use uma janela anônima (Incognito)
Extensões do Chrome executam JavaScript que aparece no profiler e distorce os resultados. Incognito desativa extensões por padrão.
- Simule hardware e rede reais
Seu MacBook Pro é 5-10x mais rápido que um dispositivo médio. Use CPU throttling (4x ou 6x slowdown) e Network throttling (Fast 3G ou Slow 4G).
- Desative o cache para medir first visit
Performance panel → ⚙️ → Disable cache. Para medir usuários recorrentes, mantenha o cache ativado.
- Feche outras abas
O Chrome compartilha recursos entre abas. Abas pesadas afetam os resultados de performance da aba sendo medida.
Performance Panel
O Performance panel é o mais poderoso para debugging de runtime. Ele grava tudo que acontece no main thread e visualiza como um timeline.
- Abra DevTools → aba Performance
- Clique no ícone de gravação (círculo) ou
Ctrl+E - Realize a interação que quer medir
- Pare a gravação
- Analise o resultado
Para medir o carregamento de página: clique no ícone de reload (seta circular) — ele grava enquanto recarrega.
Para medir uma interação específica: grave, realize a ação (clique, scroll, input), pare. O timeline mostrará exatamente o que aconteceu durante aquela interação.
O flame graph mostra as chamadas de função no tempo:
- Eixo X → tempo (esquerda = início, direita = fim)
- Eixo Y → call stack (topo = função inicial, base = funções mais internas)
- Largura → tempo gasto naquela função
O que procurar:
- Barras largas → funções que levam muito tempo
- Barras vermelhas acima do timeline → long tasks (> 50ms)
- Gaps entre barras → tempo ocioso (pode ser rede, timers, inatividade)
Long tasks são os principais causadores de INP alto — o usuário clicou durante a long task, o handler só rodou quando ela terminou.
Main thread — o mais importante. Mostra todas as tarefas JS, layout, paint e composite. Long tasks aparecem com barra vermelha no topo.
Network — waterfall de recursos carregados durante a gravação. Correlacione downloads com eventos no main thread.
Frames — cada frame renderizado. Verde = 60fps, vermelho = dropped frames (jank visível).
Timings — eventos importantes: FCP, LCP, DCL (DOMContentLoaded), Load, User Timing marks.
Web Vitals — linha dedicada para LCP, CLS e INP quando disponíveis.
Network Panel
O Network panel mostra o waterfall de todos os recursos — quando cada um foi solicitado, quanto tempo levou e em qual fase.
Fases de cada recurso no waterfall
- DNS Lookup (verde escuro)
Se estiver longo: falta um preconnect para esse domínio externo. DNS lookup é o custo de encontrar o servidor na rede.
- TCP + SSL Handshake (laranja)
Se estiver longo: preconnect resolve isso — estabelece TCP + TLS antecipadamente. HTTP/2 e HTTP/3 reduzem esse custo em requisições subsequentes.
- TTFB — Waiting (verde claro)
Se estiver alto: problema no servidor ou rede. Soluções: CDN, caching agressivo, SSG/ISR para eliminar processamento server-side.
- Content Download (azul)
Se estiver longo: recurso muito grande ou conexão lenta. Soluções: Brotli/gzip, otimização de imagens, code splitting.
Muitos recursos pequenos com gap entre eles podem indicar HTTP/1.1 sem multiplexing. Migre para HTTP/2.
Priority column — mostra a prioridade do browser para cada recurso. A imagem LCP deve aparecer como "Highest". Se não estiver, adicione fetchpriority="high".
Initiator — mostra o que causou o download. Útil para rastrear de onde veio um recurso inesperado ou pesado.
Size vs Transfer Size — Size é o original, Transfer Size é após compressão. Se forem iguais, o servidor não está comprimindo (problema).
Throttling — selecione "Slow 4G" para simular condições reais de usuários móveis. A diferença no waterfall é geralmente reveladora.
Memory Panel
O Memory panel encontra memory leaks — memória alocada mas nunca liberada, que cresce até o browser ficar lento ou travar.
Identificando leaks com Heap Snapshot
- Tire um snapshot inicial (Snapshot 1)
- Realize a ação suspeita várias vezes (abra/feche modais, navigate, interaja com a feature)
- Tire outro snapshot (Snapshot 2)
- No Snapshot 2, selecione "Objects allocated between Snapshot 1 and Snapshot 2"
Objetos que crescem sem limite entre os snapshots são candidatos a leak.
- Event listeners não removidos
O exemplo mais comum. Um componente que adiciona um listener em
windowoudocumentsem fazer cleanup no unmount. - setInterval / setTimeout não cancelados
Timers continuam rodando após o componente ser desmontado, segurando referências de closure.
- Closures segurando objetos grandes
Uma função que referencia um objeto grande em closure vai impedir que o GC colete esse objeto enquanto a função existir.
- Maps e Sets globais sem limpeza
Caches em variáveis globais que nunca são limpas crescem indefinidamente. Use WeakMap/WeakSet para referências que devem ser coletadas com o objeto.
Coverage Panel
O Coverage panel mostra qual porcentagem do JS e CSS baixado é realmente executado na página atual.
DevTools → Menu (⋮) → More tools → Coverage. Clique em "Start instrumenting coverage and reload page". Interaja com a página e analise os resultados.
A coluna Unused Bytes é o mapa do tesouro: um bundle de 500KB com 300KB não utilizados indica que code splitting agressivo vai ajudar muito.
Candidato a dynamic import. Se uma biblioteca inteira aparece com 0% de uso, provavelmente está sendo importada indiretamente. Investigue com bundle analyzer.
Candidato a PurgeCSS ou critical CSS extraction. CSS de componentes não renderizados na página atual não precisa estar no bundle inicial.
Lighthouse
Scores (0-100):
- 90-100: Verde — bom
- 50-89: Amarelo — precisa melhorar
- 0-49: Vermelho — ruim
Seções do relatório:
- Metrics — LCP, FCP, TBT, CLS, Speed Index com valores e thresholds
- Opportunities — melhorias com estimativa de ganho em segundos
- Diagnostics — problemas identificados sem estimativa direta
- Passed audits — o que já está funcionando bem
O Lighthouse simula um Moto G4 com conexão 4G lenta. Seus scores de Lighthouse podem ser muito diferentes dos Core Web Vitals reais (que vêm do CrUX).
Use o Lighthouse para:
- Identificar problemas e oportunidades específicas
- Medir progresso entre deploys (antes vs depois de uma otimização)
- CI/CD gates (falhar o build se o score cair abaixo de um threshold)
Use o PageSpeed Insights para ver o impacto em usuários reais (CrUX data).
No último artigo desta série, fechamos com Monitoramento — como medir a performance de usuários reais em produção com a Web Vitals API, RUM e gates de CI/CD.
As minhas notas
Selecione um trecho e use Destacar no menu (somente neste aparelho).