October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

JavaScript Event Loop Explained: Call Stack, Microtasks, and Async Execution

Understand JavaScript run-to-completion, browser task and microtask scheduling, and why await pauses an async function without blocking the main thread.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

JavaScript runs synchronous code on a call stack, one job at a time. In a browser, the host event loop schedules later work such as timer callbacks as tasks, while Promise reactions and queueMicrotask() callbacks run as microtasks. After a task finishes, the browser processes pending microtasks before moving on to later task work; that distinction explains the order of many asynchronous callbacks.

What the call stack does

The call stack tracks the execution contexts that are active right now. Calling a function adds its execution context to the top of the stack; returning removes it. The stack is not a callback queue: it describes nested, currently executing work.

On a JavaScript agent, a job runs to completion before another job is processed. As MDN puts it, “Each job is processed completely before any other job is processed.” Consequently, long-running synchronous work keeps that agent busy. A timer or Promise reaction cannot interrupt a synchronous function midway, and in a browser this can also delay UI responsiveness.

The JavaScript language’s execution model and a browser’s scheduling model are related, but they are not the same thing. The browser host decides when platform work can arrange for JavaScript callbacks to run. The MDN JavaScript execution model describes agents, execution contexts, and run-to-completion; the WHATWG HTML Standard defines the browser event-loop model.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How browser tasks and microtasks differ

A browser event loop coordinates task work and microtasks. Tasks include work such as starting a script, dispatching certain events, or running a timer callback. The host model uses task sources and scheduling choices; it is misleading to imagine every kind of browser callback waiting in one universal, strictly ordered FIFO queue.

Promise reaction callbacks—such as functions registered with .then()—and callbacks passed to queueMicrotask() use the microtask queue. In the usual browser model, after a task completes, the browser performs a microtask checkpoint and drains the queue until it is empty. If a microtask adds another microtask, that new callback is processed in the same drain before later task work. A chain that keeps replenishing the queue can therefore delay other tasks and rendering opportunities. See MDN’s guide to microtasks.

Trace a timer and a Promise reaction

Consider this browser example:

console.log("start");
setTimeout(() => console.log("timer task"), 0);
Promise.resolve().then(() => console.log("promise microtask"));
console.log("end");
  1. console.log("start") runs immediately.
  2. setTimeout() registers a timer callback. A delay of 0 makes the callback eligible as soon as the applicable timer constraints allow; it does not run synchronously or guarantee immediate execution.
  3. Promise.resolve().then(...) registers a Promise reaction, which is scheduled as a microtask.
  4. console.log("end") runs before the current synchronous job finishes.
  5. At the microtask checkpoint, the Promise reaction runs. The timer callback is task work and runs later when the host selects its task.

For the usual browser behavior, the output order is start, end, promise microtask, then timer task. Promise reactions are deferred even when the Promise is already fulfilled. The Promise constructor’s executor is a different moment: it is called synchronously when the constructor runs, while a registered reaction such as a .then() callback is deferred. MDN explains these distinctions in Using promises.

What async and await change

Calling an async function starts executing its body and returns a Promise. When execution reaches await, the function suspends its continuation until the awaited value settles. Even when that value is an already-fulfilled Promise—or a plain value that is treated as a fulfilled Promise—the continuation is deferred rather than continuing synchronously at the await point.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This suspension does not block the main thread: unrelated code can run while the async function is waiting. But await does not make CPU-heavy synchronous work non-blocking. A loop that runs before yielding still occupies the JavaScript agent until it finishes. If the awaited Promise rejects, the rejection is thrown at the await point and can be handled with try/catch.

For details, see MDN’s reference for await.

How to reason about an unfamiliar example

  1. Mark the synchronous statements that run before the current job completes.
  2. Identify which callbacks are Promise reactions or queueMicrotask() callbacks and which are host-scheduled tasks such as timer callbacks.
  3. After the current task’s synchronous work finishes, account for the microtask checkpoint and include microtasks added by other microtasks.
  4. Only then consider later task work. For browser code, remember that host scheduling and task sources matter; do not infer a precise order between unlike tasks from a single global-queue picture.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why runtime matters

The ordering above describes common browser behavior. The HTML event loop is a host specification, and event loops do not necessarily correspond one-to-one with implementation threads. Node.js and other JavaScript hosts have their own scheduling details, so browser task-order examples should not be transferred wholesale to them. For exact behavior in another runtime, consult that runtime’s documentation.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.