DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
← From Beginner to Expert in Fundamentals of Frontend
  • Scope & Closures
  • Asynchronous JavaScript
  • DOM Manipulation
  • ES6+ to 2026
  • Execution Context & Call Stack
  • Hoisting: var, let, const & Functions
  • Data Types & Type Coercion
  • Prototypes & the this Keyword
  • The Event Loop Deep Dive
  • Higher-Order Functions, Currying & Functional Patterns
  • Callbacks, Promises & Async/Await
  • Event Delegation & DOM Optimization
  • Destructuring, Spread/Rest & Modern Syntax
  • ES Modules & the Fetch API
  • Memory Management & Garbage Collection
  • Debouncing, Throttling & Performance Patterns
  • Design Patterns in JavaScript
  • Proxies, Reflect & Symbols
  • JavaScript Optimizations & Best Practices
  • JavaScript Interview Questions (30 MCQs)
← From Beginner to Expert in Fundamentals of Frontend

Event Delegation & DOM Optimization

18 min read
Event DelegationEvent BubblingDocumentFragmentIntersectionObserverMutationObserverDOM PerformancestopPropagation

Event Propagation

When an event fires, it travels through the DOM in three phases:

  1. Capture Phase: Window → Document → ... → Target's parent
  2. Target Phase: The element itself
  3. Bubble Phase: Target's parent → ... → Document → Window

Event Delegation

Instead of adding event listeners to every child, add ONE listener to a parent and use event.target to identify which child was clicked.

// ❌ Bad: 1000 listeners for 1000 items
document.querySelectorAll("li").forEach(li => {
  li.addEventListener("click", handleClick);
});

// ✅ Good: 1 listener on the parent
document.querySelector("ul").addEventListener("click", (e) => {
  if (e.target.tagName === "LI") {
    handleClick(e.target);
  }
});

stopPropagation vs preventDefault

MethodDoesExample
stopPropagation()Stops event from bubbling upPrevent parent click handler from firing
preventDefault()Stops default browser actionPrevent form submission, link navigation
stopImmediatePropagation()Stops other listeners on same elementMultiple handlers on same element

DOM Manipulation Performance

// ❌ Bad: Causes reflow on EVERY iteration
for (let i = 0; i < 1000; i++) {
  const li = document.createElement("li");
  li.textContent = `Item ${i}`;
  document.getElementById("list").appendChild(li); // 1000 reflows!
}

// ✅ Good: DocumentFragment — ONE reflow
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const li = document.createElement("li");
  li.textContent = `Item ${i}`;
  fragment.appendChild(li);
}
document.getElementById("list").appendChild(fragment); // 1 reflow!

Batch Style Changes

// ❌ Bad: Triggers reflow for each style change
element.style.width = "100px";
element.style.height = "200px";
element.style.background = "red";

// ✅ Good: One class change = one reflow
element.classList.add("styled-box");

Intersection Observer

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src;
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll("img[data-src]").forEach(img => observer.observe(img));

Mutation Observer

const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    console.log("DOM changed:", mutation.type);
  });
});

observer.observe(document.body, {
  childList: true,
  subtree: true,
  attributes: true
});

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.