Skip to content

Event Loop

This lesson explains Event Loop in JavaScript with beginner-friendly examples, practical use cases, and clear best practices.

JavaScript Event Loop Overview

The JavaScript event loop is the mechanism that allows JavaScript to handle asynchronous tasks while staying single-threaded. It coordinates the call stack, Web APIs, callback queue, microtask queue, and rendering process so JavaScript can run timers, promises, events, and API callbacks without blocking the browser.

Understanding the event loop is essential for mastering asynchronous JavaScript, promises, async/await, timers, event handlers, UI updates, performance optimization, and interview questions about execution order.

Event Loop Concept Description Common Usage
Call Stack Runs synchronous JavaScript code. Function execution.
Web APIs Browser-provided async features. Timers, fetch, DOM events.
Callback Queue Stores timer and event callbacks. setTimeout and event handlers.
Microtask Queue Stores promise callbacks. then, catch, finally, queueMicrotask.
Event Loop Moves queued tasks to the call stack when it is empty. Async execution control.
Rendering Browser updates the UI between event loop cycles. Layout, paint, animations.

JavaScript Event Loop Example

console.log("Start");

setTimeout(function() {
  console.log("Timer");
}, 0);

Promise.resolve().then(function() {
  console.log("Promise");
});

console.log("End");

The output is Start, End, Promise, and then Timer. Synchronous code runs first, promise microtasks run next, and timer callbacks run after that.

Top 10 JavaScript Event Loop Examples

The following examples show common event loop patterns used in asynchronous JavaScript, promises, timers, async/await, DOM events, and interview questions.

# Example Syntax
1 Synchronous Code console.log("Start"); console.log("End");
2 setTimeout Callback setTimeout(function() { console.log("Timer"); }, 0);
3 Promise Microtask Promise.resolve().then(function() { console.log("Promise"); });
4 queueMicrotask queueMicrotask(function() { console.log("Microtask"); });
5 Async Await async function run() { await Promise.resolve(); console.log("Done"); }
6 Fetch Callback fetch("/api/users").then(function(res) { return res.json(); });
7 DOM Event Task button.addEventListener("click", function() { console.log("Clicked"); });
8 setInterval Task setInterval(function() { console.log("Tick"); }, 1000);
9 Nested Timer setTimeout(function() { setTimeout(function() { console.log("Nested"); }, 0); }, 0);
10 Promise Before Timer Promise.resolve().then(cb); setTimeout(cb, 0);

Best Practices

  • Keep synchronous JavaScript work small to avoid blocking the UI.
  • Use promises and async/await for readable asynchronous workflows.
  • Remember that promise callbacks run before timer callbacks.
  • Use requestAnimationFrame() for visual updates and animations.
  • Use debouncing or throttling for frequent events such as input, scroll, and resize.
  • Break large tasks into smaller chunks when processing heavy data.
  • Avoid creating endless microtask loops that block rendering.
  • Use browser developer tools to inspect long tasks and performance issues.

Common Mistakes

  • Assuming setTimeout(..., 0) runs immediately.
  • Forgetting that promise microtasks run before timer callbacks.
  • Blocking the call stack with heavy synchronous loops.
  • Expecting UI rendering to happen while JavaScript is still running.
  • Creating too many microtasks and delaying rendering.
  • Using timers for animations instead of requestAnimationFrame().
  • Ignoring performance problems caused by long-running JavaScript tasks.

Key Takeaways

  • The event loop coordinates synchronous and asynchronous JavaScript execution.
  • The call stack runs synchronous code first.
  • Promise callbacks run in the microtask queue.
  • Timer and event callbacks run in the callback queue.
  • Microtasks run before normal callback queue tasks.
  • Understanding the event loop helps explain async behavior and execution order.

Pro Tip

For JavaScript event loop interview questions, remember this order: synchronous code first, promise microtasks second, timer and event callbacks third. This rule explains many common async output questions.