Como Medir o Desempenho de JavaScript
Problemas de desempenho em JavaScript são fáceis de sentir, mas difíceis de identificar. Sua aplicação parece lenta, as interações travam e os usuários percebem — mas sem as ferramentas de medição adequadas, você está apenas supondo. Este artigo aborda técnicas práticas de medição de desempenho de JavaScript usando APIs modernas de navegadores e DevTools, para que você possa encontrar gargalos reais e corrigir as coisas certas.
Principais Conclusões
- Diferencie entre testes sintéticos (laboratório) e monitoramento de usuários reais (RUM) — use ferramentas de laboratório para diagnosticar, dados de campo para validar.
- O painel Performance do Chrome DevTools exibe tarefas longas, gráficos de chama e árvores de chamadas para profiling prático.
- A Performance API (
performance.now(),performance.mark(),performance.measure()) fornece temporização precisa e programática que se integra com o DevTools. PerformanceObserverautomatiza a coleta de entradas para monitoramento em produção, incluindo detecção de tarefas longas.- Interaction to Next Paint (INP) é o Core Web Vital mais intimamente ligado à responsividade. A execução de JavaScript é um dos principais contribuintes, juntamente com trabalho de estilo, layout e pintura.
Testes de Laboratório vs. Dados de Usuários Reais
Antes de escolher uma ferramenta, entenda os dois tipos de medição de desempenho de JavaScript:
- Testes sintéticos (laboratório) executam seu código em um ambiente controlado. Ferramentas como Lighthouse e Chrome DevTools fornecem resultados repetíveis e depuráveis. Ótimas para desenvolvimento e pipelines de CI.
- Dados de campo (RUM) capturam o que os usuários reais experimentam. Ferramentas como Chrome User Experience Report (CrUX) ou plataformas RUM mostram o desempenho real em diferentes dispositivos e redes.
Use ferramentas de laboratório para diagnosticar problemas. Use dados de campo para confirmar que eles importam.
Profiling de JavaScript no Chrome DevTools
O Chrome DevTools é o ponto de partida mais prático para métricas de desempenho de JavaScript. Abra o painel Performance, clique em gravar, interaja com sua página e depois pare.
O que procurar:
- Long Tasks — qualquer tarefa bloqueando a thread principal por mais de 50ms aparece em vermelho. Essas frequentemente atrasam interações do usuário. Ferramentas modernas também podem exibir Long Animation Frames, que fornecem insights mais detalhados sobre frames lentos que afetam a responsividade.
- Visualizações Call Tree / Bottom-Up — identifique quais funções consomem mais tempo de execução.
- Flame chart — visualize a pilha de chamadas ao longo do tempo para identificar trabalho síncrono custoso.
O Firefox DevTools oferece um profiler similar. Ambas as ferramentas são gratuitas, não requerem configuração e funcionam em qualquer site.
Medindo o Tempo de Execução de JavaScript com a Performance API
Para medição de desempenho de JavaScript precisa e programática, use a Performance API nativa do navegador.
Usando performance.now()
performance.now() retorna um timestamp de alta resolução em milissegundos, relativo à origem de tempo da página — tornando-o mais confiável que Date.now() para temporizar código.
const start = performance.now()
runExpensiveOperation()
const duration = performance.now() - start
console.log(`Levou ${duration}ms`)
Usando performance.mark() e performance.measure()
Para temporização estruturada em múltiplos pontos, use marcas e medições. Isso se integra diretamente com DevTools e PerformanceObserver.
performance.mark('fetch-start')
const data = await fetchData()
performance.mark('fetch-end')
const measure = performance.measure('fetch-duration', 'fetch-start', 'fetch-end')
console.log(measure.duration) // milissegundos
As medições aparecem no painel Performance do Chrome DevTools sob a trilha Timings, facilitando a correlação com outras atividades na thread principal.
Discover how at OpenReplay.com.
Automatizando Medições com PerformanceObserver
PerformanceObserver permite que você reaja a entradas de desempenho conforme elas acontecem — útil para monitoramento em produção.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.name, entry.duration)
}
})
observer.observe({ type: 'measure', buffered: true })
Você também pode observar entradas longtask para detectar bloqueio da thread principal em sessões de usuários reais.
Core Web Vitals e INP: As Métricas que Importam
Os Core Web Vitals do Google são as métricas padrão de desempenho de JavaScript para experiência do usuário. A mais relevante para JavaScript é Interaction to Next Paint (INP) — ela mede a latência de todas as interações (cliques, toques, entrada de teclado) ao longo da vida útil de uma página.
Um INP acima de 200ms é um sinal de alerta. Acima de 500ms é ruim. Execução pesada de JavaScript durante manipuladores de eventos é a causa mais comum.
Use a biblioteca web-vitals para medir INP em campo:
import { onINP } from 'web-vitals'
onINP(({ value }) => console.log('INP:', value))
Para SPAs, observe que navegações suaves (mudanças de rota sem carregamentos completos de página) são capturadas apenas parcialmente pelas métricas de navegação padrão. O suporte do navegador para medição de navegação suave ainda está evoluindo, então instrumentar transições de rota manualmente usando performance.mark() pode ajudar a preencher lacunas.
Escolhendo a Ferramenta Certa
| Objetivo | Ferramenta |
|---|---|
| Depuração rápida | console.time() / console.timeEnd() |
| Temporização precisa | performance.now() |
| Temporização estruturada e visual | performance.mark() + performance.measure() |
| Monitoramento automatizado | PerformanceObserver |
| Profiling completo de página | Painel Performance do Chrome DevTools |
| Pontuações de auditoria + dados de campo | Lighthouse + CrUX |
Conclusão
A medição eficaz de desempenho de JavaScript começa com a ferramenta certa para a pergunta certa. Use DevTools para fazer profiling e explorar, a Performance API para instrumentar caminhos de código específicos, e Core Web Vitals — especialmente INP — para entender o que os usuários realmente experimentam. Meça primeiro, depois otimize.
Perguntas Frequentes
performance.now() retorna um timestamp de alta resolução relativo à origem de tempo da página, oferecendo precisão de submilissegundos. Date.now() depende do relógio do sistema, que pode ser afetado por ajustes de relógio e oferece apenas resolução de milissegundos. Para fazer benchmark de execução de código, performance.now() é a escolha mais precisa e confiável.
Use um PerformanceObserver configurado para observar entradas do tipo longtask. Qualquer tarefa excedendo 50ms na thread principal é sinalizada como uma tarefa longa. Ao coletar essas entradas em produção, você pode identificar quais interações do usuário acionam trabalho bloqueante e priorizar a otimização onde ela mais importa.
Interaction to Next Paint mede a latência de todas as interações durante uma visita à página e reporta a pior delas. First Input Delay capturava apenas o atraso da primeira interação. INP fornece uma visão mais completa da responsividade em tempo de execução, razão pela qual o Google substituiu FID por INP como Core Web Vital em março de 2024.
Sim. Coloque chamadas performance.mark() antes e depois de sua expressão await, depois chame performance.measure() com ambos os nomes de marca para calcular o tempo decorrido. A entrada de medição resultante inclui a duração completa da operação assíncrona e aparece na trilha Timings do DevTools para correlação visual.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.