
Understand the JavaScript event loop in depth. Learn how the call stack, microtasks, and macrotasks work together to handle asynchronous code efficiently, keeping your applications fast, predictable, and responsive.
Martin Ferret
November 18, 2025
JavaScript runs on a single thread. You can think of it as a single-lane road where only one car, one piece of code, can drive at a time.
That car represents the call stack, the place where your currently executing functions live.
When a car needs to stop for gas, for example when a function triggers an asynchronous operation like fetch() or setTimeout(), it doesn’t block the entire road. It simply pulls over. Other cars can continue driving.
Once the gas is ready, the car rejoins the traffic flow through one of two queues: the microtask queue (for Promises, queueMicrotask, or MutationObserver) or the macrotask queue (for setTimeout, setInterval, or DOM events).
The event loop acts as the traffic controller.
It continuously checks if the road is clear. When it is, it takes the next waiting car from the queues and lets it pass, always giving priority to microtasks before macrotasks.
This system is what allows JavaScript to appear asynchronous, even though it never runs more than one task at a time.
The JavaScript runtime is built around three essential structures.
The Call Stack
This is where synchronous code executes. Each function call is pushed onto the stack and popped off when it completes.
The Heap
A large region of memory where objects, closures, and references are stored.
The Queues
These hold asynchronous tasks waiting to run once the call stack is empty.
The event loop monitors all of these. It ensures that tasks are processed in the right order, that the main thread never stays idle, and that asynchronous operations never block execution.
To understand how asynchronous code executes, you need to distinguish between microtasks and macrotasks.
Microtasks such as Promises and queueMicrotask are executed immediately after the current stack clears, before the next rendering cycle. They have higher priority and will always run before any macrotask begins.
Macrotasks such as timers, events, or I/O operations run after all microtasks have finished. Each macrotask represents a new “tick” of the event loop.
Example:
console.log('Start');
setTimeout(() => console.log('Macrotask: Timeout'), 0);
Promise.resolve().then(() => console.log('Microtask: Promise'));
console.log('End');
Output:
Start
End
Microtask: Promise
Macrotask: Timeout
The promise callback executes before the timeout because microtasks are always processed first.
Consider a common UI pattern. When a user clicks a button, you show a loading message and then fetch data from an API.
button.addEventListener('click', () => {
list.textContent = 'Loading...';
fetch('/api/items')
.then(res => res.json())
.then(data => {
list.textContent = data.join(', ');
});
});
The text “Loading…” appears immediately because setting it is a synchronous operation.
The fetch() call runs asynchronously, and when the data is ready, the promise resolves and updates the DOM.
The event loop coordinates this without freezing the interface or blocking user interaction.
Understanding the event loop is essential for writing efficient JavaScript.
Performance
It helps you prevent blocking operations that slow down rendering or user input.
Predictability
It allows you to reason about task order, avoiding subtle async timing bugs.
Frameworks
Every modern frontend or backend framework such as React, Angular, or Node.js relies on the event loop’s scheduling model.
Control
Once you understand microtask and macrotask behavior, you can deliberately control when and how asynchronous code runs.
The event loop is the heartbeat of the JavaScript runtime. It manages everything that happens, from synchronous calls to asynchronous operations, one step at a time.
When you master how it moves between the stack, microtasks, and macrotasks, asynchronous JavaScript stops feeling random. It becomes predictable, transparent, and fully under your control.
Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Angular Signal Forms — Set-up and validation rules
The article explains Angular’s experimental Signal Forms (introduced with Angular 21), showing how they provide a third approach to building forms alongside template-driven and reactive forms by using signals to manage form data, state, and validation more directly and intuitively, including centralized, reusable validation rules and simpler access to field status like validity, errors, and user interaction.
Alain Chautard
Feb 11, 2026

Vanilla JavaScript in 2026: Why You Still Can’t Ignore It
Vanilla JavaScript in 2026: Why You Still Can’t Ignore It
Martin Ferret
Feb 3, 2026

What's New in React 19.2
Learn what's new in React 19.2: Activity for state-preserving UI, useEffectEvent for cleaner effects, compiler-powered ESLint rules, and Performance Tracks in DevTools.
Aurora Scharff
Feb 2, 2026
We can help you recruit Certified Developers for your organization or project. The team has helped many customers employ suitable resources from a pool of 100s of qualified Developers.
Let us help you get the resources you need.
