How JavaScript handles the exectution of Runtime feature..

So, till now you must be already aware that when you run a JS Code. It becomes a process. For a process, we have access to a memory area in which there are multiple components like Call Stack. But there are a few other components as well that will unravel the mystery for us.

  1. Macrotask Queue

  2. Microtask Queue

  3. Event Loop

Signaling the runtime;

As we know that any feature which is native to JS, is executed in a Synchronous fashion. At any point in time when JS encounters any particular feature that is something nonnative to JS or belongs to runtime, then JS does one very simple task. It just notifies the runtime that your feature has been called and then comes back to its normal execution state and continues with normal execution code. Apart from that behind the scene, the runtime starts executing the feature.

console.log("Start");
setTimeout(function f(){
  console.log("Timer Done");
}, 3000);
console.log("End");
Start
End
Timer Done

This will be the output for the above code.

Let's say this is a piece of code. We are running this code in JS. The first line of this code is native to JS so it will execute it synchronously and print Start, in the next line when JS detects we are calling a runtime feature. It immediately goes to the runtime for signaling starts a timer of 3s and posts that execute the callback f.

After that JS will not wait there for even a millisecond and immediately come back to the last line and print End.

Now You might be thinking what if the timer is 0 milliseconds? Then JS will wait for it. The answer is No.

JS never waits for runtime features even if there is a timer of 0 milliseconds. Runtime will take some moments to set up the timer run it and so on. This will take some milliseconds or microseconds. JS never even waits for that much time quantum.

What happens when runtime completes the task?

You might be thinking that let's say JS is executing some piece of Code and in between that runtime completes its execution, so will the JS code flow stop or not wait for it and again continue its normal execution? What will happen?

function block (){
    for(let i = 1; i <= 1000000000; i++){
        if( i % 50000000 == 0) console.log(i);
    }
}
x = -1;
setTimeout(function f() {
    console.log("Timer Done");
}, 1000);
block();
x += 10;
console.log(x);

This will be the output for the above code.

In the above JS code, there is a block function that will take surely 5 to 6 secs. Then we are also triggering a timer of 1 sec. which will run of course in a runtime environment and post-triggering the timer. we initiate a blocking loop of more than 1s. Are we going to pause the loop in between and execute the callback f. Or we will not pause?

We will never halt or pause the execution of code which is running on the main thread.

When the runtime completes its task, then it cannot halt the current execution of JS code, so what it will do is that whatever the callback function to be executed after the task is done, it sends that callback function to wait for sometimes in Macrotask Queue or Callback Queue.

This callback will wait in the queue and never halt the current execution flow. If there are more runtime features as soon as they are done their callbacks will also wait in the Macrotask Queue.

So when will these waiting callbacks be gonna get executed?

To handle the execution of these waiting callbacks. We have something called an Event loop. This is a continuous infinite running loop (till the time program is executing ) which will constantly check whether there is a function present in the Call Stack which is still executing. or if there is some piece of code left in the global Scope/area.

Till the time there is something in the Call Stack or the global area. The event loop will never allow any callback function to wait in the callback queue to start execution. Once Call Stack and the global area are empty then the event loop will take the front element waiting in the callbacks queue and push it inside the call stack and start its execution.

Till the time this callback is getting executed other callbacks have to wait in the queue. Because not this function went into the call stack. So it is a JS code getting executed in the main thread.

function block (){
    for(let i = 1; i <= 1000000000; i++){
        if( i % 50000000 == 0) console.log(i);
    }
}
x = 0;
setTimeout(function f1 () {
    console.log("Timer 1 Done");
}, 1000);

setTimeout(function f2 () {
    console.log("Timer 2 Done");
}, 0);

setTimeout(function f3 () {
    console.log("Timer 3 Done");
}, 50);

block();

setTimeout(function f4 () {
    console.log("Timer 4 Done");
}, 20);


x += 10;
console.log(x);

This will be the output of the above code.

In runtime, every timer function runs parallel and after completion of time, that function pushes in Macrotask Queue. Each native function goes into Call Stack, when Call Stack is empty and no other is left in the global area then the nonnative function will be executed. Although is already completed before native function.

Conclusion

First, all native functions or variables will execute after that nonnative functions will be executed. Which is first in the Macrotask Queue. And which nonnative function will be the first which has less time to execute. This condition only follows if there is no native function inside the native function.