Introdução: por que o perfilamento é um must-have para todo desenvolvedor
Você já escreveu um código que aparentemente funciona, mas na produção começa a "travar"? Ou talvez você tenha iniciado um servidor Node.js e, depois de alguns minutos, ele "consumia" toda a memória? Na maioria das vezes, o problema não está na linguagem, mas nos gargalos — trechos de código que são executados de forma não otimizada.
O perfilamento (profiling) é o processo de coleta de métricas sobre a execução do programa: tempo de execução das funções, consumo de memória, frequência de chamadas. Sem ele, qualquer otimização é um chute no escuro. Neste artigo, vamos explorar como perfilar código JavaScript no ambiente Node.js, encontrar "gargalos" e eliminá-los.
Você aprenderá sobre as ferramentas integradas do V8, Chrome DevTools e técnicas práticas que ajudarão a tornar seu código mais rápido.
1. Perfilamento integrado no Node.js: a flag --prof
A maneira mais simples de começar a perfilar é usar a flag --prof ao iniciar a aplicação Node.js. Ela ativa a coleta de estatísticas do V8, que são então convertidas em um relatório legível.
Como funciona
Execute sua aplicação com a flag:
node --prof app.jsApós a conclusão da execução, um arquivo chamado isolate-0x...-v8.log será criado na pasta. Estes são os dados brutos. Para obter o relatório, use o utilitário node --prof-process:
node --prof-process isolate-0x...-v8.log > profile.txtExemplo: encontrando uma função lenta
Suponha que temos o seguinte código:
function slowSort(arr) { return arr.sort((a, b) => a - b);}
function heavyComputation() { let sum = 0; for (let i = 0; i < 1e7; i++) { sum += Math.sqrt(i); } return sum;}
// Execuçãoconst data = Array.from({ length: 10000 }, () => Math.random());slowSort(data);heavyComputation();Após o perfilamento, no relatório você verá algo como:
[JavaScript]: ticks total nonlib name 120 60.0% 70.0% LazyCompile: *heavyComputation app.js:5 40 20.0% 25.0% LazyCompile: *slowSort app.js:1O número ticks mostra a quantidade de "ticks" (amostras) que ocorreram em cada função. Quanto mais ticks, mais tempo a função levou para executar. No nosso caso, heavyComputation é o principal candidato para otimização.
2. Chrome DevTools: perfilador visual para Node.js
Se o relatório textual parecer inconveniente, use o Chrome DevTools. Esta é uma interface gráfica que mostra um flamegraph (gráfico de chamas) — uma visualização da pilha de chamadas ao longo do tempo.
Conexão ao processo Node.js
Execute a aplicação com a flag --inspect:
node --inspect app.jsAbra o Chrome, na barra de endereços digite chrome://inspect. Clique em "Open dedicated DevTools for Node". Você será levado a uma interface onde pode capturar perfis.
Análise prática
Vamos considerar um exemplo com vazamento de memória:
const cache = [];
function addToCache(item) { cache.push(item);}
function processData() { for (let i = 0; i < 100000; i++) { addToCache({ id: i, data: new Array(1000).fill('x') }); }}
processData();Grave um perfil através da aba "Memory" (faça um snapshot do heap). Você verá que o array cache ocupa centenas de megabytes. O flamegraph na aba "Performance" mostrará que a função addToCache é chamada 100.000 vezes — este é o gargalo.
Solução: limitar o tamanho do cache ou usar uma estrutura com remoção automática de elementos antigos (por exemplo, um Map com limite).
3. Perfilamento com o módulo perf_hooks
Para medição pontual do tempo de execução de trechos específicos de código, use o módulo integrado perf_hooks. É um análogo do
Blogs
Book Recommendations
Leia também
Filas e tarefas em segundo plano em Kotlin: da teoria ao código real
WebSockets em Kotlin: Criando aplicações em tempo real do zero
# ou javascript:void(0): o que escolher para links JS?
Swift para programação de sistemas: uma nova ferramenta poderosa
IsNumeric em JavaScript: 5 erros fatais na validação de números