Demystifying JavaScript's Event Loop: Microtask queue (Part 2)

Demystifying JavaScript's Event Loop: Microtask queue (Part 2)

Welcome, techies! Today, we are going to explore the microtaskQueue. It is closely intertwined with the callBackQueue, and its existence is often overlooked on the Internet. However, it plays a magical role in the Event Loop.

I'm willing to bet that there's a 95% chance you haven't even heard of it. But after reading this article, you'll be confident enough to explain it to someone and have a chance to show off. 😎

Introduction

According to articles on the Internet, the microtask queue and the callback queue are similar queues but differ in their precedence (EventLoop) and the types of tasks they hold.

Precedence: After completing the Global Execution Context, the EventLoop first checks the microtask queue for pending tasks and then the callback queue.

Tasks:

Microtask queue: This queue handles responses from the Mutation Observer and the Promises, such as those from the fetch API.

Callback queue: Most web APIs, excluding the ones mentioned above (e.g., setTimeout), are handled in this queue.

Now we will continue this article by understanding two point of view over the micro task queue

Situations

1.


function getT()
{
    return (new Date()).getTime();
}

let str = getT();
console.log("start: ",getT()-str);



let promise = fetch("https://ducklogicc.blogspot.com/");

promise.then((res)=>{
    console.log("promise resolved: ",getT()-str);
}).catch((err)=>{
    console.log("promise rejected: ", getT() - str);
})

// setTimeOut

setTimeout(()=>{
    console.log("setTimeout(executed): ",getT()-str);
},300)

console.log("end ", getT() - str);

Only Callback queue: The setTimeout response is enqueued before the fetch response because the fetch response takes longer. As a result, the setTimeout response appears earlier in the console than the fetch API.

Microtask queue: This happens because the setTimeout response is sent to the callback queue first, while the microtask queue is still empty. After the Global Execution Context finishes, the task in the callback queue is executed. Then, when the microtask queue receives the response, it is also executed.

2.


function getT()
{
    return (new Date()).getTime();
}

let str = getT();
console.log("start: ",getT()-str);



let promise = fetch("https://ducklogicc.blogspot.com/");

promise.then((res)=>{
    console.log("promise resolved: ",getT()-str);
}).catch((err)=>{
    console.log("promise rejected: ", getT() - str);
})

// setTimeOut

setTimeout(()=>{
    console.log("setTimeout(executed): ",getT()-str);
},700)

console.log("end ", getT() - str);

Only Callback queue: The fetch API provided its response earlier than the setTimeout, so it was enqueued before the setTimeout response. After finishing the code, the event loop executed the responses stored in the callback queue.

Microtask queue: The microtask queue received the response and, due to precedence, JavaScript processed it and sent the response to the console. After that, the response from setTimeout entered the callback queue. Since the microtask queue was vacant at that time, the event loop prioritized the callback queue.

3.

So far, we have seen that even if the microtask queue does not exist, there is no difference in the execution of the JavaScript program. How can we confirm the accuracy of the articles claiming these things? Is there no way to confirm the existence of the microtask queue?

Now, I personally recommend thinking about the output of this code. This situation will give you the confidence in what I was discussing at the beginning of the article.


function getT()
{
    return (new Date()).getTime();
}

let str = getT();
console.log("start: ",getT()-str);

let promise = fetch("https://ducklogicc.blogspot.com/");

promise.then((res)=>{
    console.log("promise resolved: ",getT()-str);
}).catch((err)=>{
    console.log("promise rejected: ", getT() - str);
})

// setTimeOut

setTimeout(()=>{
    console.log("setTimeout(executed): ",getT()-str);
},10)

//Time consuming Block
while(getT() != str+1000){}

console.log("end ", getT() - str);

Only Callback queue: Ahh…!

I failed to explain this because the setTimeout is set to only 10 milliseconds, which is undoubtedly faster than the response we are waiting to be fetched.

Microtask queue: Haha!

That's what I have been saying since the beginning. Now, the setTimeout is definitely executed first, but it is inside the callback queue. The fetch response is enqueued later in the microtask queue, but since the microtask queue has higher precedence, the EventLoop sends the fetch response to the call stack first, and then the setTimeout one.

From the above situation, it is evident and proven that the microtask queue exists.

Thanks for reading!!!

Did you find this article valuable?

Support Sahitya Aryan by becoming a sponsor. Any amount is appreciated!