DEV Community

Cover image for Understanding the Node.js event loop phases and how it executes the JavaScript code.

Understanding the Node.js event loop phases and how it executes the JavaScript code.

Sumedh Nimkarde on February 08, 2020

I believe if you are reading this, you must have heard about the famous event loop that Node.js has, how it handles the concurrency mechanism in No...
Collapse
 
nickytonline profile image
Nick Taylor

I love this explanation from Jake Archibald with great visuals.

I mention it in my frontend resources post with some other goodies

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde

It is great indeed! Thanks for sharing it here.

Collapse
 
artoodeeto profile image
aRtoo

Hello nice article. I have clarifying question process.nextTick() happens after all the event loop phases or before the phases?

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde

Hi, process.nextTick callbacks are executed immediately. As mentioned, whenever the event loop encounters process.nextTick, it finishes its current callback execution(no matter what phase it is in), then pauses and executes our process.nextTick callback first after which it resumes to the phase which it left its work on.

I hope you this answers your question.

Collapse
 
artoodeeto profile image
aRtoo

Thank you for the response sir. Last question it only happens in their execution context right? say I have this code:

console.log('bar')

function f() {
 process.nextTick(console.log('foo'))
}

f()
setImmediate( ()=> console.log('immediate') )

output:
bar
immediate
foo

even though I called f() first before setImmediate

Thread Thread
 
lunaticmonk profile image
Sumedh Nimkarde

Hey, pardon for the late reply. Yes, it happens in the execution context. Thanks for reminding, I think I forgot to mention this term in the article! By the way, I think you may have mistaken for the output, after executing, the output seems to be:

bar
foo
immediate

Here is how it happens:

  1. console.log gets logged
  2. f is called. f()
  3. now, everything happens according to the f() context. i.e process.nextTick will execute with priority. If there are any other setTimeout, setImmediate callbacks, they will be pushed to the respective queues and executed.
  4. lastly, when the function returns, we come back to the last setImmediate, and execute the callback.
Thread Thread
 
artoodeeto profile image
aRtoo

I never tried my code. I thought process.nextTick will be push to event loop and setImmediate will run next since its in the higher or outer execution context.

anyway thanks for explaining. :)

Thread Thread
 
kausachan profile image
kausachan • Edited

Every code gets executed inside execution context only right? then why that question was raised? Am I not understanding something? pls help!

Collapse
 
dhireneng profile image
dhiren-eng • Edited

Hi,

The blog is very helpful but the outputs of 2 small code snippets in your blog is where i am getting confused. Could you please tell me where I am going wrong ? Your help will be REALLY valuable. Im getting confused in process.nextTick() .

function main() {
  setTimeout(() => console.log('1'), 50);
  process.nextTick(() => console.log('2'));
  setImmediate(() => console.log('3'));
  process.nextTick(() => console.log('4'));
}
main();

In the above code all the callbacks from microtasks queue are executed first so the below output :

2
4
3
1

But in the the last code snippet you mentioned as example :

const fs = require('fs');

function main() {
 setTimeout(() => console.log('1'), 0);
 setImmediate(() => console.log('2'));

 fs.readFile('./xyz.txt', (err, buff) => {
  setTimeout(() => {
   console.log('3');
 }, 1000);

 process.nextTick(() => {
  console.log('process.nextTick');
 });

 setImmediate(() => console.log('4'));
});

setImmediate(() => console.log('5'));

setTimeout(() => {
 process.on('exit', (code) => {
  console.log(`close callback`);
 });
}, 1100);

}
main();

In the above code process.nextTick does not seem to be executed first as seen in the below output :

1
2
5
process.nextTick
4
3
close callback

Could you please explain why process.nextTick is not being executed first ??

Collapse
 
trunghahaha profile image
trunghahaha • Edited

I think because process.nextTick is in fs.readFile block, so when event loop comes to poll phase, it has to wait for i/o task is completed before executing anything else so every callbacks in this block are put to corresponding phase queue, now, there is nothing to do more in this phase, the event loop will move to check phase and print 5 to console, next iteration when event loop comes to i/o phase, it check that i/o task is done so it prints 'process.nextTick' -> check phase( print '4') -> closing phase -> timer phase (print '3')

Collapse
 
dhireneng profile image
dhiren-eng

Okay ! Did not read the code carefully that's y d confusion . Thanks a lot :)

Thread Thread
 
lunaticmonk profile image
Sumedh Nimkarde

Hey! Pardon for the late reply. As trunghahaha said, process.nextTick is wrapped inside the fs.readFile, hence, the event loop gets to know about it only when the callback of fs.readFile is executed, right? Hence, such behaviour.

Collapse
 
kaqqao profile image
Bojan Tomic

Isn't it great how setImmediate is less immediate than nextTick which isn't executed in the next tick but in the current? 🤪

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde

Yes, it is indeed. It is also said that they should have been named the other way i.e setImmediate should have been named process.nextTick and vice versa.

Collapse
 
abdallahmansorr profile image
Abdallah Mansour

Thank you, great one 💙
But I have a little question..
What's the difference between fs.readFile and fs.Promises.readFile , in other words where will be fs.Promises.readFile priority in the context of this post

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde • Edited

Since, promises come under microtasks, as far as my knowledge, fs.Promises.readFile gets the priority but the only catch is that the handler passed to .then(fn) i.e fn here is pushed to the queue (registered) only after the promise is resolved/rejected.

Whereas, if it is a fs.readFile, its callback is immediately registered by the event loop when it(the event loop) encounters the fs.readFile operation.

Thus, if you do something like:

fs.promises.readFile(`./file.txt`).then((buff) => {
    console.log(`> resolved promise`);
  });


  fs.readFile(`./file.txt`, (err, buff) => {
    if (err) throw err;
    console.log(`> not a promise`);
  });

You may see that the output will be:

> not a promise
> resolved promise

Hope this helps!

Collapse
 
abdallahmansorr profile image
Abdallah Mansour • Edited

Thank you for replying 💙 , but for this piece of code I put fs.promise.readFile upfront so it would(should) be resolved and pushed to the queue early before settimeout, can you clarify why this output .. !



const fs=require('fs')

// text.txt file just contains 'Hello World'
const read=fs.promises.readFile('./text.txt','utf-8')

read.then(()=>{
    console.log('from promise')
})

//just looping to ensure that the file has finished reading
for(let i=0;i<10000;i++){
    console.log('looping...')
}

setTimeout(() => {
    console.log('from setTimeout')
}, 0);


//--output--
// looping...
// from setTimeout
// from promise


Collapse
 
sanyaldips93 profile image
Dipayan Sanyal • Edited

I really enjoyed this article. Clear and on point. Thanks for this.

Might I add, if anyone needs an in-depth answer on what 'tick' is, the following image can help.

image: dev-to-uploads.s3.amazonaws.com/i/...

src : stackoverflow.com/questions/198226...

author : josh3736

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde

👌🏼👌🏼

Collapse
 
ashutoshningot profile image
Ashutosh Ningot

One of the best explanation for the event loop.

Are the following will execute in the same fashion?
1.With main
function main() {
........Some Code.......
}
main();
OR
2.Without main
........Some Code.......

Collapse
 
ismail9k profile image
Abdelrahman Ismail

Thank you for this amazing post 🙋🏻‍♂️

Collapse
 
lunaticmonk profile image
Sumedh Nimkarde

Hey Abdelrahman, Thanks for reading! Glad you liked it!

Collapse
 
thawkin3 profile image
Tyler Hawkins

This is one of the best explanations of the Node.js event loop out there! Nicely done.

Collapse
 
omkar8089 profile image
Omkar Shete

Very well explained.
Everything is explained in simple words, that will help everyone to understand how event loops exactly work in Node. JS.
Thank you for the Awesome article.

Collapse
 
sonalprabhu profile image
sonalprabhu

Hello!
It's a great article and I thoroughly enjoyed it!
One question though!
Can the maximum number of callbacks in a queue to be executed set by us for performance benefits? Or is it system defined?