Otimização de desempenho de aplicações JavaScript para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que o desempenho do JavaScript é importante?

\n

JavaScript (especialmente no ambiente Node.js) tornou-se a base do desenvolvimento web moderno. A velocidade de execução do código afeta não apenas a experiência do usuário, mas também a carga no servidor. Aplicações lentas perdem audiência, e requisições não otimizadas podem levar a um aumento caro na capacidade. Neste artigo, abordaremos métodos básicos, mas eficazes, de otimização de desempenho que são adequados até mesmo para iniciantes.

\n

Vamos considerar três áreas principais: programação assíncrona, gerenciamento de memória e profiling. Todos os exemplos serão em Node.js.

\n\n

1. Assincronia: Evitando o bloqueio do Event Loop

\n

O Node.js opera em modo single-thread com o Event Loop. Se você executa uma operação síncrona pesada (por exemplo, ler um arquivo grande ou um loop complexo), todo o servidor "congela" até sua conclusão. Para evitar isso, use métodos assíncronos.

\n

Exemplo ruim (código bloqueante):

\n
const fs = require('fs');\nconst data = fs.readFileSync('/bigfile.txt', 'utf8'); // Bloqueia a thread\nconsole.log('Arquivo lido');\n
\n

Exemplo bom (não bloqueante):

\n
const fs = require('fs').promises;\nasync function readFile() {\n  const data = await fs.readFile('/bigfile.txt', 'utf8');\n  console.log('Arquivo lido');\n}\nreadFile();\n
\n

Use async/await e Promises para todas as operações de entrada/saída (I/O). Isso permite que o Event Loop processe outras requisições enquanto aguarda a resposta do banco de dados ou sistema de arquivos.

\n

Dica: Evite métodos síncronos em produção

\n

Métodos como fs.readFileSync ou crypto.pbkdf2Sync são aceitáveis apenas na inicialização da aplicação. Em tempo de execução, use suas versões assíncronas.

\n\n

2. Otimização do gerenciamento de memória e vazamentos

\n

Vazamentos de memória são uma das causas comuns de queda de desempenho em aplicações Node.js. Eles ocorrem quando objetos permanecem na memória, mesmo não sendo mais necessários.

\n

Principais causas de vazamentos:

\n
    \n
  • Variáveis globais
  • \n
  • Timers não limpos (setInterval sem clearInterval)
  • \n
  • Referências fechadas em closures
  • \n
  • Listeners de eventos que não são removidos
  • \n
\n

Exemplo de vazamento através de listeners:

\n
const EventEmitter = require('events');\nconst emitter = new EventEmitter();\n\nfunction processRequest() {\n  emitter.on('data', (chunk) => {\n    // Processamento de dados\n  });\n}\n// Cada chamada a processRequest adiciona um novo listener, mas não remove o antigo!\n
\n

Solução: Remova listeners ou use once

\n
emitter.once('data', (chunk) => {\n  // Será executado apenas uma vez e removido automaticamente\n});\n
\n

Também é útil usar utilitários como heapdump para análise de memória. Mas, para começar, basta garantir que as referências a objetos não permaneçam no escopo global.

\n\n

3. Cache e Profiling

\n

O cache permite evitar a reexecução de cálculos pesados. O profiling ajuda a encontrar gargalos no código.

\n

Cache simples com Map:

\n
const cache = new Map();\n\nfunction expensiveCalculation(input) {\n  if (cache.has(input)) {\n    console.log('Do cache');\n    return cache.get(input);\n  }\n  const result = input * 1000 + Math.random(); // Simulação de lógica complexa\n  cache.set(input, result);\n  return result;\n}\n\nconsole.log(expensiveCalculation(5)); // Calcula\nconsole.log(expensiveCalculation(5)); // Do cache\n
\n

Para cenários mais complexos, use bibliotecas como node-cache ou Redis.

\n

Profiling com a ferramenta integrada do Node.js

\n

Execute a aplicação com a flag --prof:

\n
node --prof app.js\n
\n

Após parar a aplicação, um arquivo isolate-*.log aparecerá na pasta. Converta-o em

Blogs

Book Recommendations