Skip to main content

Performance | Node.js

  • Performance | Node.js

Melhorar a performance no Node.js utilizando a API de Performance

O primeiro passo para melhorar a performance de uma aplicação é entender onde estão os gargalos. A API de Performance do Node.js, através do módulo perf_hooks, permite medir o tempo de execução com alta precisão, algo que não pode ser feito com precisão usando a classe Date.

Exemplo básico de medição de tempo com perf_hooks:

const {performance} = require('node:perf_hooks');

let start = performance.now();
for (let i = 0; i < 10000; i++) {}
let end = performance.now();

console.log(end - start); // Medição mais precisa em milissegundos

A API permite marcar eventos com precisão e medir o tempo entre eles:

Marcar eventos com performance.mark:

performance.mark("loop_start");

for (let i = 0; i < 10000; i++) {}

performance.mark("loop_end");

console.log(performance.measure("loop_time", "loop_start", "loop_end"));

O uso dessas marcações pode ser útil para monitorar operações como consultas a banco de dados ou ordenações:

Exemplo de medição de operações de consulta e ordenação:

async function main(){
const querySize = 10;

performance.mark("db_query_start");
const data = fetchData(querySize);
performance.mark("db_query_end");

performance.mark("sort_start");
const sorted = sortData(data);
performance.mark("sort_end");

console.log(performance.measure("db_time", "db_query_start", "db_query_end"));
console.log(performance.measure("sort_time", "sort_start", "sort_end"));
}

Os resultados das medições podem ser exportados para ferramentas como Prometheus para monitoramento externo. Além disso, é importante limpar as marcações após seu uso:

performance.clearMarks("mark_name");
performance.clearMeasures("measure_name");

Utilizando threads para processamento pesado:

Para evitar que tarefas pesadas congelem a interface do usuário, podemos utilizar workers para processar em segundo plano:

const { Worker, isMainThread, parentPort, workerData } = require("node:worker_threads");

async function main() {
const data = await fetchData(10);
let sorted = await new Promise((resolve, reject) => {
const worker = new Worker(__filename, { workerData: data });
worker.on("message", resolve);
worker.on("error", reject);
worker.on("exit", (code) => {
if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
});
});
}

function worker() {
const data = workerData;
sortData(data);
parentPort.postMessage(data);
}

if (isMainThread) {
main().then(() => { console.log("done"); });
} else {
worker();
}

Dicas finais para otimização:

  • Meça antes de otimizar: use a API de Performance para identificar os gargalos reais.
  • Reduza dependências: elimine pacotes não utilizados e faça carregamento preguiçoso de módulos.
  • Cache e índices: use cache com cautela e crie índices nos campos consultados frequentemente no banco de dados.

Esse resumo contém as explicações principais e o código necessário para entender e aplicar a API de Performance do Node.js para otimização de aplicativos.