Performance optimization ensures your JavaScript runs fast and keeps the UI responsive. Measure first, then optimize.

Measure Before Optimizing

  console.time('operation');
// code to measure
console.timeEnd('operation');

// High-resolution timing
performance.mark('start');
// ...
performance.mark('end');
performance.measure('myOp', 'start', 'end');
console.log(performance.getEntriesByName('myOp'));
  

Use browser DevTools Performance tab and Lighthouse for profiling.

DOM Performance

Batch DOM updates

  // Slow: multiple reflows
for (let i = 0; i < 1000; i++) {
    list.innerHTML += `<li>${i}</li>`;
}

// Fast: single update
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
    const li = document.createElement('li');
    li.textContent = i;
    fragment.appendChild(li);
}
list.appendChild(fragment);
  

Cache DOM references

  // Bad: query inside loop
for (let i = 0; i < items.length; i++) {
    document.querySelector('#output').textContent = items[i];
}

// Good
const output = document.querySelector('#output');
for (let i = 0; i < items.length; i++) {
    output.textContent = items[i];
}
  

Use event delegation

One listener on parent instead of hundreds on children (see Events chapter).

Avoid Blocking the Main Thread

Break heavy work into chunks:

  function processChunk(items, index = 0, chunkSize = 100) {
    const end = Math.min(index + chunkSize, items.length);
    for (let i = index; i < end; i++) {
        processItem(items[i]);
    }
    if (end < items.length) {
        requestIdleCallback(() => processChunk(items, end, chunkSize));
    }
}
  

For CPU-intensive tasks, use Web Workers.

Memory Management

Avoid memory leaks

Common causes:

  • Forgotten event listeners
  • Closures holding large references
  • Detached DOM nodes still referenced in JS
  // Clean up
function setup() {
    const handler = () => console.log('resize');
    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
}

const cleanup = setup();
// later: cleanup();
  

WeakMap for caches

Use WeakMap so cached objects can be garbage-collected when no longer needed.

Algorithm Efficiency

Know Big-O basics:

Complexity Example
O(1) Map lookup
O(n) Single loop
O(n²) Nested loops
O(log n) Binary search
  // O(n) — use Set for O(1) lookups
const idSet = new Set(ids);
items.filter(item => idSet.has(item.id));
  

Network Performance

  • Minimize HTTP requests; bundle and compress assets
  • Use async/defer on scripts
  • Lazy load images: loading="lazy"
  • Cache API responses appropriately

JavaScript Engine Optimizations

  • Avoid changing object shapes dynamically (add properties in consistent order)
  • Prefer const/let over var
  • Monomorphic functions (consistent argument types) optimize better
  • Don’t optimize prematurely — profile first

requestAnimationFrame for Animations

  function animate() {
    // update visual state
    requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
  

Syncs with display refresh (~60fps) and pauses when tab is hidden.

Performance is an ongoing practice — profile in production-like conditions and optimize the actual bottlenecks.