Have you been using node js for a while now? Are you aware of how things work internally in node js? the queues in node js? Doesn’t matter if your answer is yes or no, I will let you in on one little secret which will clear all your doubts regarding how node js works asynchronously under the hood.
Let’s test your knowledge on node js. If you understand the queues in node js, you would be able to solve the below question.
If you guessed
15342, you understand the internal functioning of node js. Didn’t guess it right? No worries, we’ll help you through this article. Here, we would dive deep into the queues that node uses under the hood. These queues hold callback functions that are delayed due to asynchronous operations.
So, how would you know the order in which these statements are executed? Read this article and you will be able to answer most of the “find the output” questions that are thrown your way during interviews.
Before we dive into queues, let’s first understand the important components in node
Event loop, call stack, callback queues
- Event loop
The event loop is the main thread in node js. It’s main task is to monitor the callback queue and the call stack. Whenever the call stack is empty and a callback is present in the callback queue, event loops simply pushes the callback to the call stack. This is a huge topic, we’ll talk about it in some other article
- Call stack
This is where code gets executed in node. Code is pushed, executed and popped.
- Call back Queue
These queues hold callback functions to async operations after they were completed in the background. They operate in FIFO manner(First in First out).
Types of callback queues in node js
What the hell is this? Well, this is an acronym that I came up with to remember the order of priorities of these queues
1. M – Microtask queue
This queue has the highest priority. It is broken down into 2 queues
First one holds the callbacks delayed by process.nextTick.
Each iteration of the event loop is called a tick. So passing a callback to this function is like instructing node js to execute it before the next tick(aka iteration) of the event loop starts and after completion of the current operation
Second holds the callbacks delayed by promises
Promises are mainly used for asynchronous operations. A promise has 3 states
a. Pending – initial stage, operation is neither resolved nor rejected
b. Fulfilled – operation was completed successfully
c. Rejected – operation failed due to some errors
So when a promise resolves or rejects, the callback associated with it is pushed into this queue
Let’s learn this with an example
Now, what should be the output here?
Here as we can see the callback from process.nextTick executes first and then the promise. So process.nextTick queue has a higher priority.
2. T – Timer queue
Functions from this queue are next in order after the microtask queue. These include callbacks that execute after a set period of time(setTimeout, setInterval).
An important point to note here is that these functions don’t execute after the exact time specified has passed but rather anytime after the exact time has passed.
Let’s understand this with an example
Ideally, it should log
But it logs some number greater than
1000. So the callback function passed to setTimeout does not execute exactly after 1s but anytime after 1s has passed.
The event loop goes to this queue only after dealing with all asynchronous operations. Let’s understand this with another example
What’s the output of the above code?
Some people might say it’s
312. Because 0 is passed as a second arg to setTimeout and it would execute immediately. But the correct output is
321, because initially the last line gets executed and setTimeout’s and promise’s callback would be added to their respective queues. Since the microtask queue has higher priority, it is considered first and then setTimeout.
3. I – I/O queue
These include file and network operations like reading, writing to a file, etc. Node js provides us a way to asynchronously carry out these operations. After completion of these operations, node pushes callbacks to this queue. The event loop then handles these callbacks.
Let’s verify the order of queues we have studied so far with an example
Create a new file test.js and add the below code to it
What’s the output?
Hence, we have verified the order now
4. C – Check queue
Then event loop executes functions in this queue immediately after the I/O queue is completed. We can add callbacks here using the setImmediate function.
Difference between process.nextTick, setTimeout and setImmediate
A lot of developers scratch their heads over this question. It is also a common interview question.
The priority goes like this – process.nextTick > setTimeout > setImmediate
Let’s verify the priority with an example
The output is
As we can see they were not executed in the order they were written.
process.nextTick blocks the event loop. This is because all callbacks passed to these fires before the event loop continues whereas setImmediate does not block the event loop. The event loop fires the callback in its next iteration
A challenge for you. Predict the output of the below code in the comment section with an explanation
5. C – Close queue
This queue includes callbacks of close events. For eg when a stream or server closes. It is majorly used for cleaning the state of the application. Also, it makes sense to consider this last because why would you do something after the server closes?
I hope you understood the queues that node uses under the hood. Also, read about the various phases of the event loop, it’s nothing but the order in which these queues execute. If you think I’ve missed something feel free to comment below.
Happy Coding 🙂