Promise Hacks Out, queueMicrotask() In

Jiya AgrawalJiya Agrawal
3 min read

Stop turning functions into promises just for async execution - Meet queueMicrotask()

If you’ve ever wrapped a function in Promise.resolve().then(...) just to make it run asynchronously, you’re not alone.
It’s a common trick and it work, but it’s not the most intentional way to do it.

JavaScript actually gives us a dedicated API for this exact purpose: queueMicrotask().

The Backstory: Microtasks vs Macrotasks

To understand why queueMicrotask() exists, we need to zoom in on the JavaScript event loop.

JavaScript execution is single-threaded, but it’s designed to handle asynchronous events. The event loop processes tasks in two main queues:

  1. Macrotask queue → Timers (setTimeout, setInterval), UI rendering, network callbacks, etc.
    These are scheduled after the current stack finishes and after all microtasks are cleared.

  2. Microtask queue → Promise .then() callbacks, MutationObserver callbacks, and… queueMicrotask().
    These run immediately after the current stack finishes but before any macrotasks.

    That difference is huge:

Output :

A

D

B - microtask

C - macrotask

Microtasks always jump the line in front of macrotasks.

The Old Hack: Promises for Microtasks

Before queueMicrotask() existed, the easiest way to get into the microtask queue was:

It works, but it comes with:

  • Unnecessary Promise creation overhead.

  • Slightly less clear intent, looks like you’re working with promises, but you’re not.

  • A bit of mental friction for newcomers who expect .then() to mean “waiting for some async operation”.

The Modern Way: queueMicrotask()

queueMicrotask() was introduced to solve exactly this problem:
Schedule a function to run as a microtask, without pretending it’s about Promises.

Things to keep in mind regarding queueMicrotask()

  • Always runs in the microtask queue (just like .then() callbacks).

  • No promise object is created - it’s lightweight.

  • Executes after the current synchronous code finishes, but before any macrotask.

When to Use queueMicrotask()

  • Deferring work until after the current synchronous operation finishes, without waiting for the next macrotask.

  • Avoiding promise creation overhead when all you want is microtask scheduling.

  • Library development where precise async ordering matters.

  • Preventing race conditions - for example, ensuring callbacks run after all sync setup is complete.

Pros

  • Lighter and more explicit than wrapping in Promise.resolve().then(...).

  • Clear signal to readers: "I want this to run in the microtask phase."

  • Slight performance edge in tight loops or high-frequency async scheduling.

Cons (Shared with Promises)

  • Can starve the event loop if abused (e.g., recursively queuing microtasks).

  • No way to cancel once scheduled.

  • Runs so soon that it can block rendering if the work is heavy.

TL;DR

  • queueMicrotask() is like .then() callbacks, but faster and more explicit.

  • Use it when you want microtask timing without faking it with Promises.

  • Don’t abuse it in long-running loops, or you might block UI updates.

If you’ve been using Promises just to get microtask behavior - it’s time to stop.
queueMicrotask() was literally made for that.

If you enjoyed this article and want to discover more such lesser-known but powerful JavaScript, ReactJS, NextJS features, follow me for more insights.
LinkedIn
Twitter

0
Subscribe to my newsletter

Read articles from Jiya Agrawal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jiya Agrawal
Jiya Agrawal