<?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.us-east-2.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>HTTP Just Got Its First New Request Method in Years — Meet QUERY</title>
      <dc:creator>Supratik Das</dc:creator>
      <pubDate>Sat, 04 Jul 2026 16:49:11 +0000</pubDate>
      <link>https://dev.to/supratikdas01/http-just-got-its-first-new-request-method-in-years-meet-query-23a</link>
      <guid>https://dev.to/supratikdas01/http-just-got-its-first-new-request-method-in-years-meet-query-23a</guid>
      <description>&lt;p&gt;If you've built APIs for any length of time, you've almost certainly hit this wall: you need to fetch data based on a complicated set of filters, but &lt;code&gt;GET&lt;/code&gt; can't carry a body, and cramming a nested filter object into a query string turns into an unreadable, size-limited mess. So you reach for &lt;code&gt;POST&lt;/code&gt; instead — and now your "read" operation looks like a "write" to every cache, proxy, and retry mechanism between your client and your server.&lt;/p&gt;

&lt;p&gt;That mismatch has existed since the early days of HTTP. As of June 2026, it doesn't have to anymore.&lt;/p&gt;

&lt;p&gt;The IETF has published &lt;strong&gt;RFC 10008: The HTTP QUERY Method&lt;/strong&gt; as a Proposed Standard — the first genuinely new, general-purpose HTTP method to reach standardization in years. It was authored by Julian Reschke, James M. Snell (Cloudflare), and Mike Bishop (Akamai), and it gives the web a method that behaves like &lt;code&gt;GET&lt;/code&gt; in terms of safety and cacheability, while carrying a request body like &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem QUERY was built to solve
&lt;/h2&gt;

&lt;p&gt;HTTP developers have historically had exactly two tools for "give me data based on these parameters," and neither one is quite right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET&lt;/code&gt; puts everything in the URI.&lt;/strong&gt; That's semantically clean — the resource is fully identified by the URL, so caching, bookmarking, and safe retries all just work. But it falls apart once your query gets complex:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's no reliable, agreed-upon size limit. A request might pass through several intermediaries that each impose their own cap, and RFC 9110 only recommends 8,000 octets as a rough floor — not a guarantee.&lt;/li&gt;
&lt;li&gt;Structured data — nested filters, arbitrary JSON — is awkward and expensive to squeeze into a URL-safe string. Anyone who's base64-encoded a JSON blob into a query parameter knows the pain.&lt;/li&gt;
&lt;li&gt;URIs get logged, cached by browsers, and passed around far more casually than request bodies do, which becomes a real problem the moment your query includes anything sensitive.&lt;/li&gt;
&lt;li&gt;Every distinct set of parameters is technically a distinct resource, which is rarely what you actually mean semantically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;POST&lt;/code&gt; solves the size and encoding problems&lt;/strong&gt;, since the payload lives in the body instead of the URL. But it throws away the one property that made &lt;code&gt;GET&lt;/code&gt; useful: nothing in HTTP's method semantics tells a cache, proxy, or client whether a given &lt;code&gt;POST&lt;/code&gt; is safe to retry or safe to cache. Some &lt;code&gt;POST&lt;/code&gt; endpoints mutate state, some don't — and HTTP itself can't tell the difference, so every intermediary has to assume the worst.&lt;/p&gt;

&lt;p&gt;The workaround many APIs settled on — a &lt;code&gt;GET&lt;/code&gt;/&lt;code&gt;POST&lt;/code&gt;/&lt;code&gt;GET&lt;/code&gt; dance to search, materialize a result resource, then fetch it — was really just people improvising a method that HTTP didn't have.&lt;/p&gt;

&lt;h2&gt;
  
  
  What QUERY actually does
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt; takes the request semantics of &lt;code&gt;GET&lt;/code&gt; and pairs them with the request-body mechanics of &lt;code&gt;POST&lt;/code&gt;. Here's the comparison at a glance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;GET&lt;/th&gt;
&lt;th&gt;QUERY&lt;/th&gt;
&lt;th&gt;POST&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not guaranteed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idempotent&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not guaranteed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query lives in the URI&lt;/td&gt;
&lt;td&gt;Yes, by definition&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cacheable&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Only for a subsequent GET/HEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request body&lt;/td&gt;
&lt;td&gt;No defined semantics&lt;/td&gt;
&lt;td&gt;Expected&lt;/td&gt;
&lt;td&gt;Expected&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code&gt;QUERY&lt;/code&gt; request targets a resource (via the URI, same as &lt;code&gt;GET&lt;/code&gt;) and encloses content describing how that resource should be queried — arbitrary JSON, SQL, GraphQL, XML, whatever the server is willing to accept. The server processes that content safely and idempotently, then returns the result.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;QUERY&lt;/code&gt; is registered in the IANA HTTP Method Registry as both safe and idempotent, this isn't something you have to document in your API reference and hope people read — any generic HTTP client, proxy, or cache can treat &lt;code&gt;QUERY&lt;/code&gt; requests correctly without knowing anything specific about your API. Retrying a &lt;code&gt;QUERY&lt;/code&gt; after a network hiccup is always safe, exactly like retrying a &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A basic QUERY request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;QUERY&lt;/span&gt; &lt;span class="nn"&gt;/products&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shop.example.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"electronics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"lt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inStock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-rating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server responds the same way it would to any successful &lt;code&gt;GET&lt;/code&gt; — a &lt;code&gt;200 OK&lt;/code&gt; with the representation the client asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accept-Query: telling clients what you speak
&lt;/h2&gt;

&lt;p&gt;Since a &lt;code&gt;QUERY&lt;/code&gt; body's meaning depends entirely on its &lt;code&gt;Content-Type&lt;/code&gt; — unlike WebDAV's older safe-body methods (&lt;code&gt;PROPFIND&lt;/code&gt;, &lt;code&gt;REPORT&lt;/code&gt;, &lt;code&gt;SEARCH&lt;/code&gt;), which are all tied to a single XML media type — a server needs a way to advertise which query languages it actually understands. That's what the new &lt;code&gt;Accept-Query&lt;/code&gt; response header is for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A client can send a &lt;code&gt;HEAD&lt;/code&gt; or &lt;code&gt;OPTIONS&lt;/code&gt; request first, read &lt;code&gt;Accept-Query&lt;/code&gt;, and pick a format the server supports — instead of guessing and getting back a &lt;code&gt;415 Unsupported Media Type&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Location vs. Content-Location: don't mix these up
&lt;/h2&gt;

&lt;p&gt;RFC 10008 introduces the idea of an "equivalent resource" — a conceptual resource derived from the target URI plus the request content. A server can expose that resource through two different headers, and confusing them is the most common mistake teams are likely to make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Content-Location&lt;/code&gt;&lt;/strong&gt; points to a snapshot of &lt;em&gt;this specific result&lt;/em&gt;. It's useful for caching the answer to a query that already happened.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Location&lt;/code&gt;&lt;/strong&gt; points to a URI the client can &lt;code&gt;GET&lt;/code&gt; later to &lt;em&gt;repeat this exact query&lt;/em&gt; without resending the body. It turns an expensive &lt;code&gt;QUERY&lt;/code&gt; into a cheap, cacheable &lt;code&gt;GET&lt;/code&gt; for next time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mix these up and your caching layer will start serving stale results or the wrong data entirely — &lt;code&gt;Content-Location&lt;/code&gt; is a snapshot, &lt;code&gt;Location&lt;/code&gt; is a live, repeatable query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching a body is harder than caching a URL
&lt;/h2&gt;

&lt;p&gt;This is the part of the spec worth reading twice if you run a CDN or reverse proxy. A &lt;code&gt;QUERY&lt;/code&gt; response is cacheable, but the cache key has to incorporate the &lt;em&gt;entire normalized request body&lt;/em&gt;, not just the URI. That means a cache has to read and normalize the whole payload before it can even check for a hit — normalizing away things like content-encoding differences or JSON key ordering, but only in ways that don't change how the server actually interprets the query. Get the normalization wrong and you'll get false-positive cache hits, which the spec's Security Considerations section calls out explicitly as a real risk, not a theoretical one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The catch: CORS preflights
&lt;/h2&gt;

&lt;p&gt;If you're calling a &lt;code&gt;QUERY&lt;/code&gt; endpoint from browser JavaScript, there's one thing to plan for: &lt;code&gt;QUERY&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; on the CORS-safelisted method list. Every cross-origin &lt;code&gt;QUERY&lt;/code&gt; call will trigger an &lt;code&gt;OPTIONS&lt;/code&gt; preflight first, exactly like a &lt;code&gt;POST&lt;/code&gt; with a non-simple &lt;code&gt;Content-Type&lt;/code&gt; already does today. It's rarely a reason to avoid &lt;code&gt;QUERY&lt;/code&gt;, but it is a reason not to be surprised when your network waterfall grows an extra round trip on hot paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where things stand today
&lt;/h2&gt;

&lt;p&gt;Publishing a Proposed Standard doesn't mean the whole ecosystem wakes up supporting it the next morning. As of mid-2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No major browser implements &lt;code&gt;QUERY&lt;/code&gt; natively yet.&lt;/strong&gt; You can't currently send it from &lt;code&gt;fetch()&lt;/code&gt; or &lt;code&gt;XMLHttpRequest&lt;/code&gt; — this has been an open, actively discussed request against browser fetch implementations, since browsers generally allow arbitrary method names but the ergonomics for a genuinely new safe method with a body still need to be worked out across engines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server frameworks are catching up faster.&lt;/strong&gt; Runtimes and languages that let you match arbitrary method strings — Go's &lt;code&gt;net/http&lt;/code&gt; with its 1.22+ method-aware routing, for instance — can support &lt;code&gt;QUERY&lt;/code&gt; today with no changes needed, since the method name is just a string to them. Node.js's &lt;code&gt;http&lt;/code&gt; module has had community interest and active discussion around first-class support for the method as well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET 10 (LTS, released November 2025)&lt;/strong&gt; is among the first major platforms to ship built-in &lt;code&gt;QUERY&lt;/code&gt; support on both the client and server side, including a dedicated &lt;code&gt;HttpMethod.Query&lt;/code&gt; on the client.&lt;/li&gt;
&lt;li&gt;Proxies and CDNs don't yet cache &lt;code&gt;QUERY&lt;/code&gt; responses at scale by default — though the fact that two of the RFC's three authors work at Cloudflare and Akamai is a fairly strong signal about where that's headed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A sane way to roll it out
&lt;/h2&gt;

&lt;p&gt;Given where adoption stands, treat &lt;code&gt;QUERY&lt;/code&gt; as an addition, not a replacement — at least for now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep your existing &lt;code&gt;POST&lt;/code&gt;-based search or filter endpoint in place.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;QUERY&lt;/code&gt; handler alongside it that accepts the same content shape.&lt;/li&gt;
&lt;li&gt;Advertise supported query formats via &lt;code&gt;Accept-Query&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Let clients migrate to &lt;code&gt;QUERY&lt;/code&gt; as their tooling — SDKs, browsers, corporate proxies with method allow-lists — catches up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gives you the correct semantics for the clients that already understand &lt;code&gt;QUERY&lt;/code&gt;, without breaking anything for the ones that don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt; isn't a flashy addition — it's a plumbing fix. It closes a hole in HTTP's method vocabulary that's been there since the protocol's earliest days, and it does it in a way that's mechanically enforceable by generic infrastructure rather than something you have to explain in your API docs and hope developers respect. If you maintain an API with a search or filter endpoint that outgrew &lt;code&gt;GET&lt;/code&gt; years ago and settled uneasily into &lt;code&gt;POST&lt;/code&gt;, this is the method that endpoint always should have had.&lt;/p&gt;

&lt;p&gt;It'll take time for browsers, proxies, and client libraries to fully catch up. But for server-side APIs, service-to-service calls, and any client stack that already supports arbitrary HTTP methods, there's nothing stopping you from adding &lt;code&gt;QUERY&lt;/code&gt; support today.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Further reading: &lt;a href="https://www.rfc-editor.org/info/rfc10008/" rel="noopener noreferrer"&gt;RFC 10008 — The HTTP QUERY Method&lt;/a&gt; at the RFC Editor.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>http</category>
      <category>webdev</category>
      <category>api</category>
      <category>networking</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Supratik Das</dc:creator>
      <pubDate>Fri, 26 Jun 2026 16:11:21 +0000</pubDate>
      <link>https://dev.to/supratikdas01/-59ok</link>
      <guid>https://dev.to/supratikdas01/-59ok</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf" class="crayons-story__hidden-navigation-link"&gt;Why Do Promises Run Before setTimeout? (Explained Visually)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/supratikdas01" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3971720%2F47140e67-9cd9-4cea-b7ca-c3f181568b02.jpeg" alt="supratikdas01 profile" class="crayons-avatar__image" width="800" height="878"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/supratikdas01" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Supratik Das
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Supratik Das
                
              
              &lt;div id="story-author-preview-content-3990869" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/supratikdas01" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3971720%2F47140e67-9cd9-4cea-b7ca-c3f181568b02.jpeg" class="crayons-avatar__image" alt="" width="800" height="878"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Supratik Das&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf" id="article-link-3990869"&gt;
          Why Do Promises Run Before setTimeout? (Explained Visually)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Why Do Promises Run Before setTimeout? (Explained Visually)</title>
      <dc:creator>Supratik Das</dc:creator>
      <pubDate>Thu, 25 Jun 2026 16:45:11 +0000</pubDate>
      <link>https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf</link>
      <guid>https://dev.to/supratikdas01/why-do-promises-run-before-settimeout-explained-visually-gdf</guid>
      <description>&lt;p&gt;Almost every JavaScript developer has seen this:&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="s2"&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="s2"&gt;setTimeout&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;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="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="s2"&gt;Promise&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="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="s2"&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;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
Promise
setTimeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this seems strange.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setTimeout(..., 0)&lt;/code&gt; looks like it should execute immediately. So why does the Promise callback run first?&lt;/p&gt;

&lt;p&gt;The answer lies in &lt;strong&gt;JavaScript's Event Loop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=console.log(%22Start%22)%3B%0A%0AsetTimeout(()%20%3D%3E%20%7B%0A%20%20console.log(%22setTimeout%22)%3B%0A%7D%2C%200)%3B%0A%0APromise.resolve().then(()%20%3D%3E%20%7B%0A%20%20console.log(%22Promise%22)%3B%0A%7D)%3B%0A%0Aconsole.log(%22End%22)%3B" rel="noopener noreferrer"&gt;Run this in JS Visualizer — watch the queues in real time&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: JavaScript Executes Synchronous Code First
&lt;/h2&gt;

&lt;p&gt;Everything in the current script executes on the &lt;strong&gt;Call Stack&lt;/strong&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="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="s2"&gt;Start&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;prints immediately.&lt;/p&gt;

&lt;p&gt;When JavaScript encounters:&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="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="s2"&gt;setTimeout&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;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it &lt;strong&gt;does not execute the callback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead, it hands the callback to the browser (or Node.js) timer system and continues executing the current script.&lt;/p&gt;

&lt;p&gt;Next:&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="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="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="s2"&gt;Promise&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Promise is already resolved, so its &lt;code&gt;.then()&lt;/code&gt; callback is immediately scheduled in the &lt;strong&gt;Microtask Queue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Finally:&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="s2"&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;prints.&lt;/p&gt;

&lt;p&gt;Current 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
End
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: The Call Stack Becomes Empty
&lt;/h2&gt;

&lt;p&gt;At this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microtask Queue
---------------
Promise callback

Task Queue (Macrotask Queue)
----------------------------
setTimeout callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: The Event Loop Rule
&lt;/h2&gt;

&lt;p&gt;The Event Loop always follows this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Execute one Task (current script).&lt;/li&gt;
&lt;li&gt;Empty the &lt;strong&gt;entire Microtask Queue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Optionally allow rendering.&lt;/li&gt;
&lt;li&gt;Execute the next Task (Macrotask).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because Promise callbacks are &lt;strong&gt;Microtasks&lt;/strong&gt;, they execute before timer callbacks.&lt;/p&gt;

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

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Finally, &lt;code&gt;setTimeout&lt;/code&gt; Runs
&lt;/h2&gt;

&lt;p&gt;After the Microtask Queue is empty, the Event Loop processes the next Task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final 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
End
Promise
setTimeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Misconception
&lt;/h2&gt;

&lt;p&gt;❌ &lt;strong&gt;Promises have higher priority than setTimeout.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is an oversimplification.&lt;/p&gt;

&lt;p&gt;✅ The real reason is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Event Loop &lt;strong&gt;must completely drain the Microtask Queue before executing the next Task (Macrotask).&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Doesn't &lt;code&gt;setTimeout(0)&lt;/code&gt; Run Immediately?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;setTimeout(fn, 0)&lt;/code&gt; means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Execute &lt;strong&gt;after at least&lt;/strong&gt; 0 milliseconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; mean "execute instantly."&lt;/p&gt;

&lt;p&gt;Even after the timer expires, its callback waits until:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The current script finishes.&lt;/li&gt;
&lt;li&gt;The Call Stack becomes empty.&lt;/li&gt;
&lt;li&gt;Every pending Microtask has completed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Visual Timeline
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Script
│
├── console.log("Start")
├── setTimeout(...)  ─────► Browser Timer
├── Promise.then() ───────► Microtask Queue
└── console.log("End")

Call Stack Empty
        │
        ▼
Drain ALL Microtasks
        │
        ▼
Promise callback

        ▼
Run Next Task
        │
        ▼
setTimeout callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Example 2
&lt;/h2&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="mi"&gt;1&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="mi"&gt;2&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="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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&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="mi"&gt;4&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
5
3
4
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Synchronous → 1, 5
Microtasks  → 3, 4
Tasks       → 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second &lt;code&gt;.then()&lt;/code&gt; is also a Microtask, so it executes before &lt;code&gt;setTimeout&lt;/code&gt;.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Example 3
&lt;/h2&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="s2"&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="s2"&gt;Timeout&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;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="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="s2"&gt;Promise 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="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="s2"&gt;Promise 2&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="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="s2"&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;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
Promise 1
Promise 2
Timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While executing &lt;code&gt;Promise 1&lt;/code&gt;, another Microtask is scheduled. The Event Loop continues draining Microtasks until none remain.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=console.log(%22Start%22)%3B%0A%0AsetTimeout(()%20%3D%3E%20%7B%0A%20%20console.log(%22Timeout%22)%3B%0A%7D%2C%200)%3B%0A%0APromise.resolve().then(()%20%3D%3E%20%7B%0A%20%20console.log(%22Promise%201%22)%3B%0A%0A%20%20Promise.resolve().then(()%20%3D%3E%20%7B%0A%20%20%20%20console.log(%22Promise%202%22)%3B%0A%20%20%7D)%3B%0A%7D)%3B%0A%0Aconsole.log(%22End%22)%3B" rel="noopener noreferrer"&gt;Run Example 3 in JS Visualizer&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Microtask Starvation
&lt;/h2&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;loop&lt;/span&gt;&lt;span class="p"&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="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because every Microtask schedules another Microtask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setTimeout&lt;/code&gt; never executes.&lt;/li&gt;
&lt;li&gt;Rendering may be blocked.&lt;/li&gt;
&lt;li&gt;The application appears frozen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is called &lt;strong&gt;Microtask Starvation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.jsvisualizer.bytefront.dev/?code=let%20count%20%3D%200%3B%0A%0Afunction%20loop()%20%7B%0A%20%20if%20(count%2B%2B%20%3C%205)%20%7B%0A%20%20%20%20console.log(%22microtask%22%2C%20count)%3B%0A%20%20%20%20Promise.resolve().then(loop)%3B%0A%20%20%7D%0A%7D%0A%0AsetTimeout(()%20%3D%3E%20console.log(%22setTimeout%20(waited)%22)%2C%200)%3B%0Aloop()%3B" rel="noopener noreferrer"&gt;Run Microtask Starvation in JS Visualizer&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The starvation example uses a counter limit so it doesn't actually freeze your browser — but you'll see all microtasks drain before the setTimeout fires.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Script
      ↓
Drain ALL Microtasks
      ↓
Browser may Render
      ↓
Run ONE Task
      ↓
Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setTimeout(..., 0)&lt;/code&gt; schedules a &lt;strong&gt;Task (Macrotask)&lt;/strong&gt; after &lt;strong&gt;at least&lt;/strong&gt; the specified delay.&lt;/li&gt;
&lt;li&gt;Promise callbacks (&lt;code&gt;then&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, &lt;code&gt;finally&lt;/code&gt;) are &lt;strong&gt;Microtasks&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The Event Loop always drains the &lt;strong&gt;entire Microtask Queue&lt;/strong&gt; before processing the next Task.&lt;/li&gt;
&lt;li&gt;This is why Promises execute before &lt;code&gt;setTimeout()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Microtasks can enqueue more Microtasks, and they all finish before the next Task.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Want to see all of this animate live? &lt;strong&gt;&lt;a href="https://www.jsvisualizer.bytefront.dev/" rel="noopener noreferrer"&gt;Open JS Visualizer — free, no signup&lt;/a&gt;&lt;/strong&gt; and step through any example above.&lt;/p&gt;

&lt;p&gt;Related reads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.jsvisualizer.bytefront.dev/blogs/javascript-event-loop-explained" rel="noopener noreferrer"&gt;JavaScript Event Loop Explained — A Visual, Step-by-Step Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jsvisualizer.bytefront.dev/blogs/microtask-vs-macrotask-javascript" rel="noopener noreferrer"&gt;Microtask vs Macrotask in JavaScript: The Complete Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <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>
