liveBook · Manning

Microtask

As explained in Secrets of the JavaScript Ninja, Second Edition

A unit of deferred work processed after the current task and before the event loop proceeds to another task.

Suppose two clicks are waiting to be handled, and the first handler resolves a promise. The promise callback runs before the second click handler—even if that click was already queued. That is the practical importance of a microtask: it gets its turn after the current task finishes, before the event loop moves to another task. section 13.1.2

The event loop uses at least a macrotask queue and a microtask queue. Macrotasks include actions such as running mainline JavaScript, handling clicks, and handling timers. Microtasks are smaller pieces of deferred work, including promise callbacks and DOM mutation changes. Neither kind of task interrupts one that is already running. section 13.1 section 13.4

A resolved promise still waits

In a click handler, `Promise.resolve().then(() => { /* callback */ });` queues a microtask; it does not run the callback immediately. The rest of that handler finishes first. The event loop then processes the queued promise callback before taking the next waiting click task. section 13.1.2

Listing 13.2. Pseudocode for our event loop demo with two queues
<button id="firstButton"></button>
<button id="secondButton"></button>
<script>
  const firstButton = document.getElementById("firstButton");
  const secondButton = document.getElementById("secondButton");
  firstButton.addEventListener("click", function firstHandler(){ 
    Promise.resolve().then(() => {                                     #A
      /*Some promise handling code that runs for 4 ms*/                #A
    });                                                                #A

    /*Some click handle code that runs for 8 ms*/
  }); 

  secondButton.addEventListener("click", function secondHandler(){  
    /*Click handle code that runs for 5ms*/ 
  });
/*Code that runs for 15ms*/
</script>

Trace the two click handlers and the promise callback. Notice that registering the callback occurs inside the first handler, while executing it is a separate step. section 13.1.2

This priority matters to the page you see. The browser may re-render between macrotasks, but it processes queued microtasks before that opportunity. Updating application state in a microtask can therefore avoid an intermediate render that shows inconsistent state. “As soon as possible” does not mean “right now”: the current task must finish first. section 13.1 section 13.1.2

How Secrets of the JavaScript Ninja, Second Edition covers it

How deep it goes
Works through two-queue scheduling and a timed click example; does not descend into queue implementation details.
Examples
Traces two click handlers and an immediately resolved promise whose callback runs before the second click handler.
What it assumes
Assumes familiarity with JavaScript event handlers and promises while developing the distinction between macrotask and microtask queues.
What you can do after
Diagnose/debug event-handler ordering by checking when the current task ends and whether promise callbacks are queued.
How it connects
Connects microtasks to the event loop, macrotasks, promises, DOM mutations, and UI rendering.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Secrets of the JavaScript Ninja, Second Edition. The section links point to the parts of the book it draws on.