Understanding  JS  runtime environment

Understanding JS runtime environment

ยท

6 min read

Overview

In this blog, the main focus is on understanding call stack, web API, callback queue, job queue, and event loop for beginners in javascript and deep dive into learning about how they work, why we need them, and the connection between all these things.

Let's start, As Javascript is a synchronous single-threaded language means
Javascript can "only execute one command at a time in a specific order" as it can only go to the next line once the current line has been finished executing.
Whenever you run a javascript code. JS engine will create a call stack and execution context. Now, let's know about the call stack

Callstack

Javascript has one call stack and it is present inside the Javascript engine.
It handles everything to manage this execution context creation, deletion, the control and it manages a stack. This is known as the call stack.

Mainly call stack maintains the "order in which execution contexts are carried out".

Let's understand this call stack and execution context with the example :

Here we can look into the execution of the above code by the JS engine, it was as shown in the below image

When you run JS code, the JS engine will create a call stack and execution context in that. This execution context is created in two phases:
1. Memory creation phase (variable environment)
2. Code execution phase (Thread of execution)

In the memory creation phase, javascript will allocate memory to all variables and functions.
In the code execution phase, code is executed one line at a time.

So here in the above example, In the execution context, the memory creation phase stores a special value known as "undefined" for variables for functions it stores the whole code.

In the code execution phase, The value will be assigned to a variable and
when you invoke a function a brand new execution context will be created and there once the code execution and evaluation of values are done. Now it returns the control of the program, to the place where this function was invoked.

As soon as we return the value there won't be execution context (will be deleted)

So once JS completes all its work, the program is finished. The whole global execution context also delete.

So far we see synchronous code and their execution in the call stack, but how the asynchronous code will work in javascript? As javascript is synchronously single-threaded, do we need to wait when encountering fetch API call, setTimeout functionality until it completes to move on to next line of code or it will block the code execution..... No, so here in Javascript they will execute in different ways, web APIs and callback queue, and job queue will handle asynchronous code.

Web API

These are different APIs provided by the web browser that helps you build web applications.

A few that you might be familiar with are:

  • setTimeout()

  • setInterval()

  • fetch()

  • DOM APIs

Read more about Web APIs here: https://developer.mozilla.org/en-US/docs/Web/API

Callback Queue or Task queue

The Callback queue is a data structure that operates on the FIFO (first-in-first-out) principle. Callback functions that need to be asynchronously executed, are pushed onto the callback queue. These are later pushed to the Call stack to be executed (when the event loop finds an empty call stack).

How do WebAPI and Callback Queue work together?

Let's understand them, by an example:

Here the output will be:

Did you notice the delay in printing the Second statement?
Here is the flow of code, and how it executes

  • In the code first, all code will go in the call stack and global execution context,
    when printFirstStatement() invokes, creates a new execution context and performs the task, and prints the output.

  • when printSecondStatement() invokes, the call stack finds it as webAPI so it moves code to webAPI(here is setTimeout()) once it completes wait for certain seconds and move to the callback queue. At this time event loop will check whether the call stack is empty, so if it's not empty it will wait until it completes all tasks and move the callback to the call stack for further execution.

  • when printThirdStatement() invokes, in the call stack it creates a new execution context and performs the task, and prints the output meantime the printsecondStatement function was in the callback queue, the event loop will check call stack is empty, and move to the callback from the callback queue to call stack and print the output.

Job Queue or Microtask queue

Job Queue reserved only for new Promise() functionality. So when you use promises in your code, you add.then() method, which is a callback method. These thenable methods are added to Job Queue once the promise has returned/resolved and then gets executed.
Job Queue has higher priority than callback queue.
Example:

Here in the image, we can see the flow of code

  • The JS engine will create a call stack, global execution context, and promise function invokes new execution context will be created here as it finds it returning a promise.

  • promise will return a resolve or reject state.
    Once it gets resolve or reject state, the callback function in .then or .catch() will move to the job queue.

  • The event loop gets the task in the job queue, so it checks the call stack is empty, if it is empty it will move the task further the execution, if not it will wait until the call stack will be empty.

  • The last call stack will print the output and the execution context of the function will be deleted and the global execution context will also delete.

Event Loop

It will be running continuously and checks the call stack(main stack), if it has any code to execute, if not then it checks the callback queue, if the callback queue has codes to execute then it pops the code from it to the call stack for the execution.
If any code is there in the job queue, the event loop will pop the code from the job queue to the call stack and then take the callback queue code.

Conclusion

  • Javascript has one call stack and it is present inside the Javascript engine.
    Mainly call stack maintains the "order in which execution contexts are carried out".

  • JS Engine creates a call stack and global execution context when it runs a code,
    and whenever a function invokes new execution context will be created.

  • Asynchronous code execution will be handled by the web APIs and callback queue(task queue).

  • Job queue(microtask queue) is reserved only for promises in javascript, it has higher priority than the callback queue.

  • The event loop continuously monitors between call stack, callback queue, and job queue

Thanks for reading it๐Ÿ˜Š. I hope it was insightful and you got to learn something new today. If you liked the article, please post likes and share it in your circles. Share your feedback and comment away.
Let's connect on Twitter. I'd love to connect :)