Phase 5 · Advanced Node.js & ArchitectureModule 39~70 min read

Performance, Memory & Profiling

Measure latency, throughput, event-loop delay, CPU, allocation, and memory retention before applying targeted optimizations.

What you'll learn

Performance engineering begins with a reproducible workload and a budget. Measure latency distributions, throughput, CPU, event-loop delay, allocation, and retained memory before changing code.

By the end of this lesson, you'll be able to:

  • Set measurable performance budgets
  • Run controlled load tests
  • Read CPU and heap profiles
  • Confirm optimizations with before/after evidence

Core mental model

Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.

ConceptWhat it meansDecision rule
PercentileA latency threshold containing a fraction of requestsUse p95/p99 alongside median and throughput
CPU profileSamples showing where execution time is spentCapture under representative load
Heap snapshotObjects and retention paths in memoryCompare steady-state snapshots after forced workload cycles

Professional workflow

Build and verify Node.js programs from the terminal in small, observable steps.

  1. Define the performance investigation boundary: inputs, outputs, invariants, ownership, and expected failures.
  2. Design the data or message contract before choosing implementation details.
  3. Implement the smallest correct path with dependencies passed explicitly.
  4. Add validation, failure translation, cleanup, and concurrency behavior.
  5. Verify the boundary with realistic data and at least one adversarial case.
  6. Measure or observe the behavior before optimizing or extracting abstractions.

Keep the feedback loop short

Run the smallest useful command after every meaningful change. Read the complete error message before editing again, and keep inputs and outputs visible while you learn.

Guided code lab

Mark one critical operation

Performance measures attach duration to a named application boundary without relying on noisy wall-clock logging.

timed-service.js
import { performance } from 'node:perf_hooks';

performance.mark('summary:start');
const summary = await buildOwnerSummary(ownerId);
performance.mark('summary:end');
performance.measure('owner-summary', 'summary:start', 'summary:end');
const [measure] = performance.getEntriesByName('owner-summary').slice(-1);
metrics.histogram('owner_summary_ms', measure.duration);

Production practice

Contract

Every optimization names workload, environment, baseline, target metric, change, result, and correctness guard.

Verification

Warm up, hold load constant, repeat runs, inspect percentiles, use CPU/heap evidence, and rerun the full correctness suite.

Operations

Monitor latency, errors, saturation, event-loop delay, GC, RSS, heap, pool queues, and deployment regressions.

Common failure mode

Optimizing a microbenchmark while the real bottleneck is a database query or queue wait makes code harder without improving users.

Independent workshop

Profile and improve one slow endpoint without changing its contract.

Your finished workshop must include:

  • Performance budget
  • Reproducible workload
  • Baseline report
  • CPU or heap profile
  • Targeted change
  • Before/after comparison

Definition of done

Run the happy path and at least two edge cases, keep responsibilities separated, and add a short README explaining how to run the program.

Recap & quick check

Key takeaways

  • Measure before optimizing
  • Percentiles expose tails
  • Profiles identify causes
  • Memory leaks are retention
  • Correctness guards every optimization

Quick check

1. What should precede optimization?

2. What reveals CPU hotspots?

3. What often proves a leak?

Next: Phase Project: Real-Time Processing Service