<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Supratik Das</title>
    <description>The latest articles on DEV Community by Supratik Das (@supratikdas01).</description>
    <link>https://dev.to/supratikdas01</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3971720%2F47140e67-9cd9-4cea-b7ca-c3f181568b02.jpeg</url>
      <title>DEV Community: Supratik Das</title>
      <link>https://dev.to/supratikdas01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/supratikdas01"/>
    <language>en</language>
    <item>
      <title>JavaScript Event Loop Explained — A Visual, Step-by-Step Guide</title>
      <dc:creator>Supratik Das</dc:creator>
      <pubDate>Sat, 06 Jun 2026 19:22:47 +0000</pubDate>
      <link>https://dev.to/supratikdas01/javascript-event-loop-explained-a-visual-step-by-step-guide-27ie</link>
      <guid>https://dev.to/supratikdas01/javascript-event-loop-explained-a-visual-step-by-step-guide-27ie</guid>
      <description>&lt;p&gt;Ask ten developers how the JavaScript event loop works, and you'll get eleven different answers. That's because the event loop is &lt;em&gt;invisible&lt;/em&gt;. You can't console.log it. You can't set a breakpoint on it. You just have to &lt;em&gt;know&lt;/em&gt; it's there, orchestrating everything.&lt;/p&gt;

&lt;p&gt;This guide changes that. We'll walk through the event loop step by step, with code you can actually run and &lt;em&gt;see&lt;/em&gt; in &lt;a href="https://www.jsvisualizer.bytefront.dev" rel="noopener noreferrer"&gt;JS Visualizer&lt;/a&gt; — watching functions enter the call stack, callbacks move through Web APIs, and promises flush from the microtask queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Puzzle That Trips Everyone Up
&lt;/h2&gt;

&lt;p&gt;Before we dive in, try to predict the output of this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most beginners guess &lt;code&gt;A, B, C, D&lt;/code&gt;. The actual output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A
D
C
B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that surprises you, you're in exactly the right place. By the end of this article, you'll understand &lt;em&gt;why&lt;/em&gt; — and it will feel obvious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=console.log(%27A%27)%3B%0A%0AsetTimeout(()%20%3D%3E%20console.log(%27B%27)%2C%200)%3B%0A%0APromise.resolve().then(()%20%3D%3E%20console.log(%27C%27))%3B%0A%0Aconsole.log(%27D%27)%3B" rel="noopener noreferrer"&gt;Run this puzzle in JS Visualizer&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The JavaScript Runtime: Four Moving Parts
&lt;/h2&gt;

&lt;p&gt;JavaScript's runtime has four key components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Call Stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where functions execute. One at a time — JS is single-threaded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web APIs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Browser features (setTimeout, fetch, DOM events) running outside the main thread.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Callbacks from Web APIs waiting for the call stack to empty.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microtask Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Promise callbacks. Always processed before the task queue.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And then there's the &lt;strong&gt;event loop&lt;/strong&gt; itself — the coordinator. Its job: when the call stack is empty, pick the next thing to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The Call Stack — One Thing at a Time
&lt;/h2&gt;

&lt;p&gt;JavaScript is single-threaded. It has &lt;strong&gt;one call stack&lt;/strong&gt; and can do &lt;strong&gt;one thing at a time&lt;/strong&gt;. When you call a function, it gets pushed onto the stack. When it returns, it gets popped off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;processUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Supratik&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens on the call stack:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;processUser('Supratik')&lt;/code&gt; is pushed onto the stack&lt;/li&gt;
&lt;li&gt;Inside it, &lt;code&gt;greet('Supratik')&lt;/code&gt; is pushed on top&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;greet&lt;/code&gt; returns → popped off the stack&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;console.log(message)&lt;/code&gt; is pushed, executes, popped&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;processUser&lt;/code&gt; returns → popped off. Stack is empty.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 The call stack is like a stack of plates. You can only add or remove from the top. If a function calls another function, the new one goes on top and must finish before we return to the one below it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 2: Web APIs — Where Async Things Wait
&lt;/h2&gt;

&lt;p&gt;When you call &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt;, or add a DOM event listener, JavaScript doesn't handle the waiting itself. It hands the job off to &lt;strong&gt;Web APIs&lt;/strong&gt; — features provided by the browser (or Node.js runtime).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Timer done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;End&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;console.log('Start')&lt;/code&gt; → runs immediately on the call stack&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setTimeout&lt;/code&gt; → registers the callback with the Web API. The timer starts counting &lt;em&gt;outside&lt;/em&gt; the call stack. setTimeout itself returns immediately.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;console.log('End')&lt;/code&gt; → runs immediately&lt;/li&gt;
&lt;li&gt;After 2000ms, the Web API moves the callback to the &lt;strong&gt;task queue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The event loop sees the call stack is empty → picks the callback → runs it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Output: &lt;code&gt;Start → End → Timer done&lt;/code&gt;. The timer callback runs &lt;em&gt;last&lt;/em&gt;, even though it was registered second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=console.log(%27Start%27)%3B%0A%0AsetTimeout(()%20%3D%3E%20%7B%0A%20%20console.log(%27Timer%20done%27)%3B%0A%7D%2C%202000)%3B%0A%0Aconsole.log(%27End%27)%3B" rel="noopener noreferrer"&gt;Watch the timer move through Web APIs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The Task Queue (Macrotask Queue)
&lt;/h2&gt;

&lt;p&gt;When a Web API finishes its work (timer expires, fetch returns, click happens), it doesn't interrupt whatever's currently running. Instead, it places the callback in the &lt;strong&gt;task queue&lt;/strong&gt; (also called the macrotask queue).&lt;/p&gt;

&lt;p&gt;The event loop's rule is simple: &lt;em&gt;when the call stack is empty, take the first task from the queue and push it onto the stack.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Second timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Synchronous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: &lt;code&gt;Synchronous → First timeout → Second timeout&lt;/code&gt;. Both timeouts go to the task queue, and they're processed in order — but only after all synchronous code finishes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Common mistake:&lt;/strong&gt; &lt;code&gt;setTimeout(fn, 0)&lt;/code&gt; does NOT mean "run immediately." It means "run as soon as the call stack is empty and you get to the front of the queue." If there's a lot of synchronous code running, the 0ms timer could wait hundreds of milliseconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: The Microtask Queue — Promises Jump the Line
&lt;/h2&gt;

&lt;p&gt;This is where most developers get confused. There are actually &lt;strong&gt;two queues&lt;/strong&gt;, and one has priority over the other.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;microtask queue&lt;/strong&gt; holds callbacks from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Promise.then()&lt;/code&gt;, &lt;code&gt;.catch()&lt;/code&gt;, &lt;code&gt;.finally()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;queueMicrotask()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MutationObserver&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The critical rule:&lt;/strong&gt; the event loop drains the &lt;em&gt;entire&lt;/em&gt; microtask queue before touching the task queue. Every. Single. Time. If a microtask adds another microtask, that runs too — before any setTimeout callback gets a chance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Macrotask&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Microtask 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Microtask 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Synchronous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Synchronous
Microtask 1
Microtask 2
Macrotask
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though setTimeout was registered first, both Promise callbacks run before it. The microtask queue always gets priority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=setTimeout(()%20%3D%3E%20console.log(%27Macrotask%27)%2C%200)%3B%0A%0APromise.resolve().then(()%20%3D%3E%20console.log(%27Microtask%201%27))%3B%0APromise.resolve().then(()%20%3D%3E%20console.log(%27Microtask%202%27))%3B%0A%0Aconsole.log(%27Synchronous%27)%3B" rel="noopener noreferrer"&gt;Watch microtasks jump the line&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The Event Loop Algorithm
&lt;/h2&gt;

&lt;p&gt;Now we can state the event loop's actual algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run all &lt;strong&gt;synchronous code&lt;/strong&gt; on the call stack until it's empty.&lt;/li&gt;
&lt;li&gt;Drain the &lt;strong&gt;entire microtask queue&lt;/strong&gt;. If any microtask adds new microtasks, drain those too.&lt;/li&gt;
&lt;li&gt;Take &lt;strong&gt;one task&lt;/strong&gt; from the &lt;strong&gt;task queue&lt;/strong&gt; and push it onto the call stack.&lt;/li&gt;
&lt;li&gt;Go back to step 2. (Yes — microtasks are checked again after every single macrotask.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. The entire event loop is these four steps, on repeat, forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Original Puzzle
&lt;/h2&gt;

&lt;p&gt;Now let's go back to our puzzle and trace through it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// 1. Synchronous → runs immediately&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// 2. Registers with Web API → callback goes to TASK queue&lt;/span&gt;
&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// 3. Already resolved → callback goes to MICROTASK queue&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// 4. Synchronous → runs immediately&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step by step:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;console.log('A')&lt;/code&gt; → prints &lt;strong&gt;A&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setTimeout&lt;/code&gt; → callback sent to Web API → moves to task queue&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Promise.resolve().then()&lt;/code&gt; → already resolved → callback goes to microtask queue&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;console.log('D')&lt;/code&gt; → prints &lt;strong&gt;D&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Call stack is empty → drain microtask queue → &lt;code&gt;console.log('C')&lt;/code&gt; → prints &lt;strong&gt;C&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Microtask queue empty → take from task queue → &lt;code&gt;console.log('B')&lt;/code&gt; → prints &lt;strong&gt;B&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Final output: &lt;strong&gt;A, D, C, B&lt;/strong&gt;. Mystery solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: How async/await Fits In
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt; is just syntactic sugar over Promises. When you &lt;code&gt;await&lt;/code&gt; something, everything after the await becomes a &lt;em&gt;microtask&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Before await&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;After await&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// This is a microtask!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;End&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
Before await
End
After await
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"After await" runs as a microtask — same as if you'd written &lt;code&gt;Promise.resolve().then(() =&amp;gt; console.log('After await'))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=async%20function%20demo()%20%7B%0A%20%20console.log(%27Before%20await%27)%3B%0A%20%20await%20Promise.resolve()%3B%0A%20%20console.log(%27After%20await%27)%3B%0A%7D%0A%0Aconsole.log(%27Start%27)%3B%0Ademo()%3B%0Aconsole.log(%27End%27)%3B" rel="noopener noreferrer"&gt;See async/await as microtasks&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes and Misconceptions
&lt;/h2&gt;

&lt;p&gt;❌ &lt;strong&gt;Myth: setTimeout(fn, 0) runs immediately&lt;/strong&gt;&lt;br&gt;
It runs after all synchronous code AND all microtasks. The 0 is a minimum delay, not a guarantee.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Myth: Promises are asynchronous&lt;/strong&gt;&lt;br&gt;
The Promise &lt;em&gt;constructor&lt;/em&gt; runs synchronously. Only the &lt;code&gt;.then()&lt;/code&gt; callback is deferred (as a microtask).&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Myth: JavaScript is multi-threaded because it can do async things&lt;/strong&gt;&lt;br&gt;
JavaScript itself is single-threaded. Web APIs (provided by the browser) can run in parallel, but your JS code always runs one line at a time on one call stack.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript has one call stack&lt;/strong&gt; — it's single-threaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async operations&lt;/strong&gt; (timers, network) are handled by Web APIs outside the main thread.&lt;/li&gt;
&lt;li&gt;When Web APIs finish, callbacks go to the &lt;strong&gt;task queue&lt;/strong&gt; (macrotask queue).&lt;/li&gt;
&lt;li&gt;Promise callbacks go to the &lt;strong&gt;microtask queue&lt;/strong&gt;, which has higher priority.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The event loop:&lt;/strong&gt; run sync code → drain all microtasks → pick one macrotask → repeat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;async/await&lt;/strong&gt; is syntactic sugar — everything after &lt;code&gt;await&lt;/code&gt; becomes a microtask.&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;The best way to internalize this? &lt;strong&gt;See it happen.&lt;/strong&gt; Open &lt;a href="https://www.jsvisualizer.bytefront.dev" rel="noopener noreferrer"&gt;JS Visualizer&lt;/a&gt;, paste any code snippet from this article, and watch every step unfold across the call stack, queues, and event loop — in real time. It's free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jsvisualizer.bytefront.dev" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Try JS Visualizer — Free&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
