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

  1. Measure first - Use profiling tools to identify bottlenecks
  2. Don't block the main thread - Chunk work, use Web Workers
  3. Minimize DOM access - Batch operations, use virtual lists
  4. Cache wisely - Memoize expensive computations
  5. Lazy load - Load only what's needed
  6. Optimize network - Compress, cache, preload
  7. 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
README - JavaScript Tutorial | DeepML