Microtasks & Macrotasks — More On The Event Loop

This is pretty much a continuation of my initial look at the Javascript Event Loop. I’d strongly recommend reading and understand how Javascript handles running code asynchronously, specifically how the event loop, task queue, and call stack work together.
Vague Concept
We left off with the vague concept that Javascript puts tasks into a task queue before actually executing on something. This entire process of reading code, queueing up tasks, and executing tasks is the event loop. Now it’s time to dig into the event loop a little more.
Not Created Equal
It turns out that not all tasks are created the same. There are macrotasks and microtasks. In reality, these two types of tasks occupy different queues, and do they don’t mix.
For each loop of the ‘event loop’ one macrotask is completed out of the macrotask queue. After that macrotask is complete, the event loop visits the microtask queue. The entire microtask queue is completed before moving on.
Wait What…?
Yes, this is a bit counter intuitive to what you may have initial learned about the event queue, but when people refer to the event queue typically they are referring to the macrotask event queue. Each time around the loop only one task from the macrotask queue is completed, but the entire microtask queue is completed after that.
Since emptying a queue is akin to deleting it, it’s appropriate to say each loop of the event loop has it’s own microtask queue.
What Does It All Mean?
This potentially means you can get yourself into a psuedo blocking situation where a microtask queues another microtask recursively. Obviously this is a bad situation which you want to avoid. Fortunately various Javascript engines have different ways to prevent this.
From a practical standpoint, it is rare to intentionally create a recursive microtask loop, but it is important to understand the difference. Different tasks are categorized as macro or micro.
Examples of Macro
setTimeout, setInternal, setImmediate, I/O tasksExamples of Micro
process.nextTick, Promises (interesting right?)
For me the one that proved most interesting was Promises. Through my usages of Promises I never noticed any unusual behavior which would lead me to think it’s handled any differently than any other task in the event loop, but apparently it is.
However let’s imagine that Promise were treated as macrotasks. This means that a long chain of promises would actually require multiple loops through the event loop to complete. This might not be ideal.
Engine Specific
We can draw broad strokes and say most browsers may run similar, but the handling and definition of macrotask vs microtask is up to the engine specifically. This means Node might show you a different result than Chrome (actually I think they use the same engine so maybe not), and Chrome might be different than Safari.
Clarification On Terminology
In this write up I’ve been using the term task interchangeably between macrotask and microtask, much of the documentation out there refers to macrotasks as tasks and microtasks as job. Knowing this will make understanding documentation easier.
Example & More Info
There’s not a lot of write up out there about this, but I’d recommend reading Jake Archibald’s blog post about this. There is a nice example interactive example as well.
Had fun reading this? Found it useful? Recommend or share on Facebook/Twitter! Check out more posts on Always Be Coding.