Performance

Escopo: JavaScript. Visão transversal: shared/platform/performance.md.

Estas diretrizes se aplicam a hot paths (caminhos quentes, fluxos executados em volume ou frequência alta): loops apertados, handlers de requisição, processamento de stream. Fora desse contexto, prefira legibilidade. Premature optimization (otimização prematura) custa clareza sem ganho real: meça antes de otimizar.

Conceitos fundamentais

ConceitoO que é
hot path (caminho quente)Trecho de código executado em volume ou frequência alta; otimizar aqui rende
cold path (caminho frio)Trecho raro (inicialização, erro); otimizar aqui é desperdício de clareza
V8 (engine do Chrome/Node.js)Motor JavaScript do Node.js e Chrome; otimiza quando o código é previsível e mantém formas estáveis de objeto
JIT (Just-In-Time, Compilação Sob Demanda)Compilador que traduz JS para código de máquina em tempo de execução
allocation (alocação)Criação de objeto na heap; pressão de alocação custa GC
GC (Garbage Collection, Coleta de Lixo)Liberação automática de memória; pausas afetam latência
Big O (notação assintótica)Custo do algoritmo em função do tamanho da entrada (O(n), O(n²), O(log n))
profiling (perfilamento)Medição empírica de onde tempo e memória são gastos; node --prof, clinic, Chrome DevTools
stream (fluxo)Leitura/escrita em pedaços; evita carregar arquivo inteiro na memória

for...of vs forEach

forEach executa um callback (função de retorno) por iteração: há custo de chamada de função e criação de contexto de execução a cada item. Em hot paths, for...of itera diretamente sobre o iterável, sem callback.

❌ Ruim: callback alocado por iteração
function calculateTotalRevenue(orders) {
  let total = 0;
  orders.forEach((order) => {
    total += order.amount;
  });

  return total;
}
✅ Bom: for...of sem overhead de callback
function calculateTotalRevenue(orders) {
  let total = 0;
  for (const order of orders) {
    total += order.amount;
  }

  return total;
}

Set para membership

Array.includes() percorre o array do início ao fim: O(n) por verificação. Set.has() resolve em O(1) via hash. Para listas fixas verificadas com frequência, defina o Set uma vez no módulo e reutilize.

❌ Ruim: Array.includes percorre tudo a cada chamada
const PREMIUM_CATEGORIES = ["electronics", "jewelry", "watches"];

function filterPremiumProducts(products) {
  const premiumProducts = products.filter((product) =>
    PREMIUM_CATEGORIES.includes(product.category)
  );

  return premiumProducts;
}
✅ Bom: Set.has resolve em O(1)
const PREMIUM_CATEGORIES = new Set(["electronics", "jewelry", "watches"]);

function filterPremiumProducts(products) {
  const premiumProducts = products.filter((product) =>
    PREMIUM_CATEGORIES.has(product.category)
  );

  return premiumProducts;
}

ID: UUID v4 vs UUID v7

crypto.randomUUID() gera UUID (Universally Unique Identifier, Identificador Único Universal) v4, que é aleatório. Inserções aleatórias fragmentam o índice primário progressivamente. UUID v7 é time-ordered: insere sempre próximo ao fim da B-tree, sem fragmentação. Veja o impacto no banco em sql/conventions/advanced/performance.md.

❌ Ruim: crypto.randomUUID() é v4: random, fragmenta índice
function createOrder(request) {
  const orderId = crypto.randomUUID(); // v4: random, page splits no banco

  return saveOrder({ id: orderId, ...request });
}
✅ Bom: UUID v7: time-ordered, sequencial no índice
import { v7 as uuidv7 } from "uuid";

function createOrder(request) {
  const orderId = uuidv7(); // time-ordered: sequencial no índice, sem fragmentação

  return saveOrder({ id: orderId, ...request });
}

String building

Concatenação com + ou template literal dentro de um loop aloca uma nova string a cada iteração: strings são imutáveis em JavaScript. Para construir strings dinamicamente, acumule em array e chame join() no final. Uma alocação, resultado único.

❌ Ruim: nova string alocada por iteração
function buildOrderReport(orders) {
  let report = "";
  for (const order of orders) {
    report += `#${order.id}: ${order.customer}, ${order.total}\n`;
  }

  return report;
}
✅ Bom: array + join, uma alocação no final
function buildOrderReport(orders) {
  const lines = [];
  for (const order of orders) {
    lines.push(`#${order.id}: ${order.customer}, ${order.total}`);
  }

  const report = lines.join("\n");
  return report;
}

Desenvolvido por @thiagocajadev · Fork baseado no repositório pmndrs/docs · Poimandres.