Telles Logo
Pular para o conteúdo
Ver todos os artigos
jan 20, 2024
·
views
·
likes
·
8 min

DevTools: Explorando a Performance no Navegador

Um guia prático do Chrome DevTools para performance: Performance panel, flame graph, Network waterfall, Memory, Coverage e Lighthouse integrado.

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

📊Performance Panel

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.

🌐Network Panel

Waterfall de todos os recursos: quando cada um foi solicitado, fases (DNS, TCP, TTFB, download), prioridades, tamanhos.

🧠Memory Panel

Heap snapshots para encontrar memory leaks. Compare snapshots antes e depois de uma ação para ver o que cresceu.

📋Coverage Panel

Mostra qual % do JS e CSS baixado é realmente executado. Mapa do tesouro para code splitting.

Lighthouse

Auditoria completa com scores, oportunidades e diagnósticos. Integrado ao DevTools, acessível via aba Lighthouse.

🔍Performance Insights

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.

  1. Abra DevTools → aba Performance
  2. Clique no ícone de gravação (círculo) ou Ctrl+E
  3. Realize a interação que quer medir
  4. Pare a gravação
  5. 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.

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
TCP Connect
TTFB
Download
0ms100ms200ms300ms400ms
  • 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.

Memory Panel

O Memory panel encontra memory leaks — memória alocada mas nunca liberada, que cresce até o browser ficar lento ou travar.

import { useState, useEffect } from "react";

// ❌ Componente com memory leak
function LeakyTimer({ onTick }) {
  useEffect(() => {
    // Nunca limpa o intervalo — continua rodando mesmo após unmount
    const id = setInterval(() => {
      onTick((n) => n + 1);
    }, 500);
    // return () => clearInterval(id); // ← faltando cleanup
  }, []);

  return <p style={{ color: "#f38ba8" }}>❌ Timer com leak (sem cleanup)</p>;
}

// ✅ Componente sem memory leak
function CleanTimer({ onTick }) {
  useEffect(() => {
    const id = setInterval(() => {
      onTick((n) => n + 1);
    }, 500);
    return () => clearInterval(id); // ← cleanup correto
  }, []);

  return <p style={{ color: "#a6e3a1" }}>✅ Timer com cleanup correto</p>;
}

export default function App() {
  const [showLeaky, setShowLeaky] = useState(false);
  const [showClean, setShowClean] = useState(false);
  const [leakyCount, setLeakyCount] = useState(0);
  const [cleanCount, setCleanCount] = useState(0);

  return (
    <div style={{ fontFamily: "sans-serif", padding: 16 }}>
      <div style={{ marginBottom: 16 }}>
        <button
          onClick={() => setShowLeaky((v) => !v)}
          style={{ padding: "6px 14px", background: "#f38ba8", border: "none", borderRadius: 6, cursor: "pointer", marginRight: 8 }}
        >
          {showLeaky ? "Desmontar" : "Montar"} Timer com Leak
        </button>
        <span style={{ color: "#cdd6f4" }}>Ticks: {leakyCount}</span>
        {showLeaky && <LeakyTimer onTick={setLeakyCount} />}
        {!showLeaky && leakyCount > 0 && (
          <p style={{ color: "#fab387", fontSize: 13 }}>
            ⚠️ Desmontado, mas o intervalo ainda roda em background!
            Ticks continuam: {leakyCount}
          </p>
        )}
      </div>
      <div>
        <button
          onClick={() => setShowClean((v) => !v)}
          style={{ padding: "6px 14px", background: "#a6e3a1", border: "none", borderRadius: 6, cursor: "pointer", marginRight: 8 }}
        >
          {showClean ? "Desmontar" : "Montar"} Timer Limpo
        </button>
        <span style={{ color: "#cdd6f4" }}>Ticks: {cleanCount}</span>
        {showClean && <CleanTimer onTick={setCleanCount} />}
        {!showClean && cleanCount > 0 && (
          <p style={{ color: "#a6e3a1", fontSize: 13 }}>
            ✅ Desmontado e intervalo cancelado. Ticks parados em: {cleanCount}
          </p>
        )}
      </div>
    </div>
  );
}

Identificando leaks com Heap Snapshot

  1. Tire um snapshot inicial (Snapshot 1)
  2. Realize a ação suspeita várias vezes (abra/feche modais, navigate, interaja com a feature)
  3. Tire outro snapshot (Snapshot 2)
  4. 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 window ou document sem 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.

Como acessar

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.

🟡JS com muitos bytes não utilizados

Candidato a dynamic import. Se uma biblioteca inteira aparece com 0% de uso, provavelmente está sendo importada indiretamente. Investigue com bundle analyzer.

🔵CSS com muitos bytes não utilizados

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

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).

Artigos relacionados