JAVASCRIPT

JavaScript Event Loop: Syntax, Usage, and Examples

The JavaScript event loop is a mechanism that manages asynchronous operations, allowing JavaScript to execute non-blocking code despite being single-threaded. It ensures that tasks like user interactions, network requests, and timers are handled efficiently.

How the JavaScript Event Loop Works

JavaScript uses an event-driven model where asynchronous tasks are queued and executed after synchronous tasks complete. The event loop continuously checks the call stack and task queue, processing queued tasks when the stack is empty.

Understanding the Call Stack

JavaScript executes functions in a last-in, first-out (LIFO) manner using the call stack. When a function is invoked, it is pushed onto the stack and removed once it completes execution.

function greet() {
  console.log("Hello!");
}

greet(); // "Hello!"

Here, greet is added to the stack, executed, and then removed.

Task Queue and the Event Loop

Asynchronous tasks such as setTimeout, promises, and DOM events are added to a task queue and executed when the stack is clear. The event loop ensures that these tasks are handled in order.

console.log("Start");

setTimeout(() => {
  console.log("Inside timeout");
}, 0);

console.log("End");

Despite setTimeout being set to 0ms, it runs after "End" because JavaScript first completes all synchronous tasks before checking the queue.

When to Use the JavaScript Event Loop

The event loop plays a key role in managing JavaScript’s execution model. It is useful in several scenarios:

  1. Handling asynchronous operations such as HTTP requests, file reading, and timers.
  2. Improving performance by preventing long-running synchronous code from blocking execution.
  3. Managing animations and real-time user interactions without freezing the UI.
  4. Handling promises and async/await operations efficiently.
  5. Executing code at appropriate times based on task priority.

Examples of the JavaScript Event Loop

Using setTimeout to Delay Execution

A common use case is scheduling a function to execute later using setTimeout.

console.log("Before delay");

setTimeout(() => {
  console.log("This runs after 2 seconds");
}, 2000);

console.log("After delay");

"Before delay" and "After delay" are logged first because setTimeout places the function in the task queue, and the event loop waits for the stack to clear before executing it.

Processing Multiple Asynchronous Tasks

If multiple tasks are scheduled, they execute in order as the event loop cycles through them.

console.log("First");

setTimeout(() => console.log("Second"), 1000);
setTimeout(() => console.log("Third"), 500);

console.log("Fourth");

The output will be:

First → Fourth → Third → Second

Using Promises in the Event Loop

Promises have higher priority than regular tasks in the event loop and run before setTimeout callbacks.

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);
Promise.resolve().then(() => console.log("Promise resolved"));

console.log("End");

The output will be:

Start → End → Promise resolved → Timeout

This happens because promise callbacks are placed in the microtask queue, which is processed before the task queue.

Learn More About the JavaScript Event Loop

Microtasks vs. Macrotasks in the Event Loop

JavaScript has two types of queues:

  • Microtasks: Higher-priority tasks that run before macrotasks. Includes promises and queueMicrotask().
  • Macrotasks: Lower-priority tasks that run after microtasks. Includes setTimeout, setInterval, and DOM events.

console.log("Start");

setTimeout(() => console.log("Macrotask"), 0);
Promise.resolve().then(() => console.log("Microtask"));

console.log("End");

The output will be:

Start → End → Microtask → Macrotask

Using async/await with the Event Loop

async/await simplifies working with asynchronous code by making it look synchronous while still using the event loop.

async function fetchData() {
  console.log("Fetching data...");
  await new Promise(resolve => setTimeout(resolve, 2000));
  console.log("Data received!");
}

console.log("Before function call");
fetchData();
console.log("After function call");

The output will be:

Before function call → Fetching data... → After function call → Data received!

Even though fetchData contains an await, execution continues with the next synchronous statement until the promise resolves.

Event Loop and Single-Threaded JavaScript

JavaScript is single-threaded, meaning it can only run one task at a time. However, the event loop allows non-blocking operations by offloading tasks to the Web API, which handles them asynchronously before placing them in the queue.

console.log("Script start");

setTimeout(() => console.log("Timeout 1"), 0);
setTimeout(() => console.log("Timeout 2"), 0);

console.log("Script end");

The synchronous tasks (logs) execute first, followed by setTimeout callbacks.

Preventing Event Loop Blocking

Long-running synchronous tasks can freeze the UI, so using techniques like setTimeout or requestAnimationFrame can prevent this.

function longTask() {
  console.log("Start task");
  setTimeout(() => console.log("Task completed"), 0);
}

console.log("Before task");
longTask();
console.log("After task");

Splitting tasks using setTimeout allows other queued tasks to execute without blocking execution.

The JavaScript event loop enables asynchronous programming by managing task execution order in a non-blocking way. It coordinates the call stack, task queue, and microtask queue, ensuring smooth execution of user interactions, promises, and timers.

Learn to Code in JavaScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn JavaScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH