Understanding JavaScript Event Loop, Call Stack, and Task Queue

Day 43/50 – JavaScript Interview Question? Question: What is Event Loop, Call Stack, and Task Queue in JavaScript? Simple Answer: The Call Stack tracks function execution (LIFO). The Task Queue (Callback Queue) holds callbacks from async operations. The Event Loop continuously checks if the Call Stack is empty, then moves tasks from the queue to the stack. Microtasks (Promises) have priority over Macrotasks (setTimeout). 🧠 Why it matters in real projects: Understanding the Event Loop is crucial for debugging async behavior, preventing UI blocking, and optimizing performance. It explains why promises execute before setTimeout(0), and helps you write non-blocking code in a single-threaded environment. 💡 One common mistake: Not understanding microtask vs macrotask priority, leading to unexpected execution order. Also, creating infinite microtask loops that starve the macrotask queue and freeze the UI. 📌 Bonus:  // Example demonstrating execution order console.log('1: Sync Start'); setTimeout(() => {  console.log('2: setTimeout (Macrotask)'); }, 0); Promise.resolve().then(() => {  console.log('3: Promise 1 (Microtask)'); }).then(() => {  console.log('4: Promise 2 (Microtask)'); }); console.log('5: Sync End'); // Output: // 1: Sync Start // 5: Sync End // 3: Promise 1 (Microtask) // 4: Promise 2 (Microtask) // 2: setTimeout (Macrotask) // Event Loop phases: // 1. Execute all synchronous code // 2. Execute all microtasks (Promises, queueMicrotask) // 3. Execute one macrotask (setTimeout, setInterval, I/O) // 4. Repeat // Call Stack visualization function first() {  console.log('First');  second();  console.log('First again'); } function second() {  console.log('Second');  third(); } function third() {  console.log('Third'); } first(); // Stack: [first] → [first, second] → [first, second, third] // Output: First, Second, Third, First again // Microtask vs Macrotask setTimeout(() => console.log('Macro 1'), 0); Promise.resolve()  .then(() => {  console.log('Micro 1');  Promise.resolve().then(() => console.log('Micro 2'));  })  .then(() => console.log('Micro 3')); setTimeout(() => console.log('Macro 2'), 0); // Output: Micro 1, Micro 2, Micro 3, Macro 1, Macro 2 // All microtasks complete before next macrotask! // Blocking the Event Loop (BAD!) function blockingOperation() {  const start = Date.now();  while (Date.now() - start < 3000) {  // Blocks for 3 seconds - UI freezes!  } } // Better: Break into chunks async function nonBlockingOperation() {  for (let i = 0; i < 1000; i++) {  // Do work...  if (i % 100 === 0) {  await new Promise(resolve => setTimeout(resolve, 0));  // Yields to Event Loop every 100 iterations  }  } } // Microtask starvation (infinite loop) function starveEventLoop() {  Promise.resolve().then(() => {  starveEventLoop(); // Creates endless microtasks!  // Macrotasks never run - UI freezes  }); }

To view or add a comment, sign in

Explore content categories