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.