user8942442
user8942442

Reputation: 3

Node JS event loop

I am reading couple of articles online regarding NodeJs.

One article is saying that the node js will first handle what ever function in the call stack and only will handle call back function when there is no function in the call stack; while in the other article, it saying that node js event loop have different phases and each phases will handle different call back.(https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)

I am quite confused with the above concept. First is in the phases of node js, I did not see any phase that are particularly designed to handle the function in call stack, second is how node js event loop can still garantee to treat the function in the call stack as top priority if the node js is designed to have different phases?

Thank you

Upvotes: 0

Views: 447

Answers (1)

jfriend00
jfriend00

Reputation: 707996

The call stack represents the current thread of execution in the Javascript interpreter. Each function that is called pushes something onto the call stack so that when it returns, the interpreter knows where to go.

The call stack literally has nothing to do with the event loop. This just controls normal execution of one piece of Javascript.

So, let's say that your main.js at the beginning of your nodejs program looks like this:

function a() {
    console.log("executing a()");
    b("hello");
    console.log("done executing a()");
    return;
}

function b(greeting) {
    console.log(`executing b() - was called with ${greeting}`);
    c("fred");
    console.log("done executing b()");
    return; 
}

function c(name) {
    console.log(`executing c() - was called with ${name}`);
    return;
}

a();
console.log("all done");

When the interpreter calls a(), it pushes a return address onto the stack so the interpreter knows that when a() returns, it should go and execute the next line of code after where a() was called. Then, it sets up the executing environment for the function a() it starts executing a().

Then, a() calls b("hello"). Again, the interpreter pushes another return address onto the stack so the interpreter knows where to continue executing when b() returns and it sets up the executing environment for the function b() and it starts executing b().

Then b() calls c("fred") and the process is repeated.

When c() gets to it's last line of code and executes return, the interpreter looks for the most recent return address on the stack and jumps to that point, which will be the second console.log() statement inside of b().

When b() gets to it's last line of code and executes return, the interpreter looks for the most recent return address on the stack and jumps to that point, which will be the second console.log() statement inside of a().

When a() gets to it's last line of code and executes return, the interpreter looks for the most recent return address on the stack and jumps to that point, which will be the console.log() statement right after where a() was called.

At this point, the call stack will be empty. When that last console.log("all done") statement is executed, the call stack is empty and the current function is done (remember all nodejs modules are actually in a function) and then interpreter has no more code to run.

At that point, the interpreter will first look for special things to run such as PromiseJobs (resolved promises waiting to call their .then() or .catch() handlers. If there are none of those waiting in the PromiseJobQueue, then control to the event loop.

The event loop will go through it's various phases, looking for work waiting to be executed.

Let's assume there's a timer waiting to run. The time that the timer was set for has been met or surpassed. At that point, the interpreter would take the callback associated with the timer event and call that callback. That callback would start running a sequence of Javascript code. If that callback function itself called any other functions, then the call stack would then be used to keep track of function return locations. When that timer callback eventually returns back from executing, then control again goes back to the event loop and it resumes checking its various phases for any pending work to be executed. If something is found, the callback corresponding to that event is then called and so on...

I did not see any phase that are particularly designed to handle the function in call stack

The call stack is not part of the event loop. It's a mechanism for managing function calls in the core Javascript interpreter (as described above). If you had a Javascript implementation with no event loop (which is possible), then you would still have a call stack to manage the calling of functions and the returning from those function calls.

second is how node js event loop can still guarantee to treat the function in the call stack as top priority if the node js is designed to have different phases

This is just a misunderstanding since the call stack is not part of the event loop or its phases. It is a mechanism for running Javascript and executing and returning from function calls. It is not connected to the event loop.

Another way to think about this is that control only returns back to the event loop when whatever Javascript was currently running and each function in it has returned and the call stack is now empty. When the call stack is empty (meaning the first function that started off this piece of Javascript is now done), then control returns back to the event loop where is can then decide if there are any events waiting to go and have their callback called so they can run. Each callback from the event loop will return with an empty call stack BEFORE the next event from the event loop gets a chance to run.

Upvotes: 1

Related Questions