Docs
README
21.3 Performance Optimization
Overview
Performance optimization is crucial for delivering fast, responsive applications. This section covers JavaScript performance techniques, profiling tools, and optimization strategies.
Performance Metrics
┌────────────────────────────────────────────────────────────────────────────┐
│ Core Web Vitals & Metrics │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ LCP (Largest Contentful Paint) ← Loading Performance │ │
│ │ Target: < 2.5 seconds │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ FID (First Input Delay) ← Interactivity │ │
│ │ Target: < 100 milliseconds │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CLS (Cumulative Layout Shift) ← Visual Stability │ │
│ │ Target: < 0.1 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ TTFB (Time to First Byte) ← Server Response │ │
│ │ Target: < 600 milliseconds │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ TTI (Time to Interactive) ← Full Interactivity │ │
│ │ Target: < 3.8 seconds │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
JavaScript Runtime Performance
Event Loop & Blocking
┌────────────────────────────────────────────────────────────────────────────┐
│ Event Loop Optimization │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Call Stack Task Queue Microtask Queue │
│ ┌───────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ │ │ setTimeout │ │ Promise.then │ │
│ │ Heavy │ │ setInterval │ │ queueMicro │ │
│ │ Sync │────┐ │ I/O callbacks │ │ task │ │
│ │ Task │ │ └───────────────┘ └───────────────┘ │
│ │ │ │ │ │ │
│ └───────────┘ │ ▼ ▼ │
│ │ ┌───────────────────────────────────────┐ │
│ ❌ BLOCKING! └──────►│ Event Loop │ │
│ │ (Can only process when stack │ │
│ Break into chunks! │ is empty - don't block!) │ │
│ └───────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Chunking Long Tasks
// ❌ Blocking - freezes UI
function processLargeArray(items) {
for (const item of items) {
heavyProcessing(item); // 10,000 items = blocked UI
}
}
// ✓ Non-blocking - chunks work
async function processLargeArrayChunked(items, chunkSize = 100) {
for (let i = 0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize);
chunk.forEach((item) => heavyProcessing(item));
// Yield to event loop between chunks
await new Promise((resolve) => setTimeout(resolve, 0));
}
}
Memory Management
Memory Lifecycle
┌────────────────────────────────────────────────────────────────────────────┐
│ Memory Lifecycle │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. ALLOCATION 2. USAGE 3. GARBAGE COLLECTION │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Primitives │ │ Read/Write │ │ Mark & Sweep│ │
│ │ Objects │ ────► │ Operations │ ────► │ Algorithm │ │
│ │ Functions │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ Memory is allocated Variables are │ │
│ when declaring used in code ▼ │
│ ┌─────────────┐ │
│ │ FREE │ │
│ │ MEMORY │ │
│ └─────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Common Memory Leaks
┌────────────────────────────────────────────────────────────────────────────┐
│ Common Memory Leaks │
├───────────────────────────────────┬────────────────────────────────────────┤
│ Leak Type │ Solution │
├───────────────────────────────────┼────────────────────────────────────────┤
│ Forgotten event listeners │ Remove listeners on cleanup │
│ Closures holding references │ Nullify references when done │
│ Detached DOM nodes │ Clear references to removed nodes │
│ Timers not cleared │ clearInterval/clearTimeout │
│ Global variables │ Use block scope, avoid globals │
│ Console.log in production │ Remove or disable in production │
└───────────────────────────────────┴────────────────────────────────────────┘
Caching Strategies
Memoization
// Without memoization - recalculates every time
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// With memoization - O(n) instead of O(2^n)
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const fibMemoized = memoize(fibonacci);
Caching Patterns
┌────────────────────────────────────────────────────────────────────────────┐
│ Caching Strategies │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Cache Hierarchy │ │
│ │ │ │
│ │ L1: In-Memory (Map/WeakMap) ← Fastest, limited size │ │
│ │ ▼ │ │
│ │ L2: Session/Local Storage ← Persistent, per-user │ │
│ │ ▼ │ │
│ │ L3: IndexedDB ← Large data, structured │ │
│ │ ▼ │ │
│ │ L4: HTTP Cache / CDN ← Network level │ │
│ │ ▼ │ │
│ │ L5: Server-side Cache (Redis) ← Shared, distributed │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Cache Invalidation Strategies: │
│ • Time-based (TTL) │
│ • Version-based (cache busting) │
│ • Event-based (on data change) │
│ • LRU (Least Recently Used) │
│ │
└────────────────────────────────────────────────────────────────────────────┘
DOM Performance
Batch DOM Operations
┌────────────────────────────────────────────────────────────────────────────┐
│ DOM Operation Optimization │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ BAD: Multiple Reflows │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ for (item of items) { │ │
│ │ container.appendChild(createEl(item)); // Reflow each time │ │
│ │ } │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ✓ GOOD: Batch with DocumentFragment │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ const fragment = document.createDocumentFragment(); │ │
│ │ for (item of items) { │ │
│ │ fragment.appendChild(createEl(item)); // No reflow │ │
│ │ } │ │
│ │ container.appendChild(fragment); // Single reflow │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ✓ BETTER: Virtual DOM or innerHTML (for large updates) │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ container.innerHTML = items.map(createHTML).join(''); │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Layout Thrashing
// ❌ Layout thrashing - read/write cycle
function badLayout() {
for (const el of elements) {
const height = el.offsetHeight; // Read - forces layout
el.style.height = height + 10 + 'px'; // Write - invalidates layout
}
}
// ✓ Batch reads and writes
function goodLayout() {
// Read all
const heights = elements.map((el) => el.offsetHeight);
// Write all
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px';
});
}
Lazy Loading
Lazy Loading Patterns
┌────────────────────────────────────────────────────────────────────────────┐
│ Lazy Loading Strategies │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Images: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ <img loading="lazy" src="image.jpg"> │ │
│ │ │ │
│ │ // Or with Intersection Observer │ │
│ │ observer.observe(img); │ │
│ │ // Load when visible │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ Code Splitting: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ // Dynamic import │ │
│ │ const module = await import('./heavy-module.js'); │ │
│ │ │ │
│ │ // Route-based splitting (frameworks) │ │
│ │ const Dashboard = lazy(() => import('./Dashboard')); │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ Data: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ // Infinite scroll / pagination │ │
│ │ // Load more data as user scrolls │ │
│ │ // Virtual lists for large datasets │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Debouncing & Throttling
┌────────────────────────────────────────────────────────────────────────────┐
│ Debounce vs Throttle │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DEBOUNCE: Wait until activity stops │
│ ───────────────────────────────────── │
│ │
│ Events: × × × × × × × × │ │
│ Time: ──────────────────────────────────────► │
│ Executes: ◆ │
│ ↑ │
│ Only after pause │
│ │
│ Use for: Search input, window resize, form validation │
│ │
│ ───────────────────────────────────────────────────────────────────── │
│ │
│ THROTTLE: Execute at most once per interval │
│ ─────────────────────────────────────────── │
│ │
│ Events: × × × × × × × × │
│ Time: ──────────────────────────────────────► │
│ Executes: ◆ ◆ ◆ ◆ │
│ ↑ ↑ ↑ ↑ │
│ Fixed intervals │
│ │
│ Use for: Scroll events, mouse move, API rate limiting │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Web Workers
Offloading Heavy Computation
┌────────────────────────────────────────────────────────────────────────────┐
│ Web Workers │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Main Thread Worker Thread │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ │ postMsg │ │ │
│ │ UI Rendering │ ─────────► │ Heavy Computation │ │
│ │ Event Handling │ │ Data Processing │ │
│ │ DOM Access │ ◄───────── │ Complex Algorithms │ │
│ │ │ postMsg │ │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │ │ │
│ │ ✓ UI stays responsive │ ✓ True parallelism │
│ │ ✓ No blocking │ ✗ No DOM access │
│ │ │ ✗ Limited APIs │
│ │
│ // Main thread │
│ const worker = new Worker('worker.js'); │
│ worker.postMessage({ data: largeArray }); │
│ worker.onmessage = (e) => console.log(e.data.result); │
│ │
│ // worker.js │
│ onmessage = (e) => { │
│ const result = heavyProcessing(e.data); │
│ postMessage({ result }); │
│ }; │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Network Optimization
Request Optimization
┌────────────────────────────────────────────────────────────────────────────┐
│ Network Optimization │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Reduce Requests: │
│ • Bundle JavaScript/CSS files │
│ • Use CSS sprites or icon fonts │
│ • Inline critical resources │
│ │
│ Reduce Size: │
│ • Enable gzip/brotli compression │
│ • Minify JavaScript/CSS/HTML │
│ • Optimize images (WebP, AVIF) │
│ • Remove unused code (tree shaking) │
│ │
│ Caching: │
│ • Set proper Cache-Control headers │
│ • Use ETags for validation │
│ • Implement Service Workers │
│ │
│ Loading Strategy: │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ <link rel="preload" href="critical.js" as="script"> │ │
│ │ <link rel="prefetch" href="next-page.js"> │ │
│ │ <link rel="preconnect" href="https://api.example.com"> │ │
│ │ <script defer src="app.js"></script> │ │
│ │ <script async src="analytics.js"></script> │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Profiling Tools
Browser DevTools
┌────────────────────────────────────────────────────────────────────────────┐
│ Performance Profiling Tools │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Chrome DevTools: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Performance Panel → Record runtime performance │ │
│ │ Memory Panel → Heap snapshots, allocation timeline │ │
│ │ Network Panel → Request waterfall, timing │ │
│ │ Lighthouse → Automated performance audit │ │
│ │ Coverage → Find unused CSS/JS │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ JavaScript APIs: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ performance.now() → High-resolution timestamps │ │
│ │ performance.mark() → Custom markers │ │
│ │ performance.measure() → Measure between marks │ │
│ │ PerformanceObserver → Observe performance entries │ │
│ │ console.time/timeEnd() → Simple timing │ │
│ │ console.profile() → CPU profiling │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Performance Optimization Checklist
┌────────────────────────────────────────────────────────────────────────────┐
│ Performance Optimization Checklist │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ JavaScript: │
│ □ Minimize bundle size (code splitting, tree shaking) │
│ □ Avoid synchronous operations (use async/await) │
│ □ Debounce/throttle event handlers │
│ □ Use Web Workers for heavy computation │
│ □ Implement proper error handling │
│ │
│ Memory: │
│ □ Remove event listeners on cleanup │
│ □ Clear timers and intervals │
│ □ Avoid creating unnecessary objects │
│ □ Use WeakMap/WeakSet for cache │
│ □ Profile for memory leaks │
│ │
│ DOM: │
│ □ Batch DOM reads and writes │
│ □ Use DocumentFragment for multiple inserts │
│ □ Leverage event delegation │
│ □ Virtual scrolling for long lists │
│ │
│ Network: │
│ □ Enable compression (gzip/brotli) │
│ □ Implement caching strategy │
│ □ Lazy load non-critical resources │
│ □ Preload critical resources │
│ │
│ Rendering: │
│ □ Optimize critical rendering path │
│ □ Minimize reflows and repaints │
│ □ Use CSS containment │
│ □ Prefer CSS animations over JS │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Key Takeaways
- •Measure first - Use profiling tools to identify bottlenecks
- •Don't block the main thread - Chunk work, use Web Workers
- •Minimize DOM access - Batch operations, use virtual lists
- •Cache wisely - Memoize expensive computations
- •Lazy load - Load only what's needed
- •Optimize network - Compress, cache, preload
- •Monitor in production - Use Real User Monitoring (RUM)
Files in This Section
- •
README.md- This documentation - •
examples.js- Performance optimization examples - •
exercises.js- Performance improvement exercises