How JavaScript is actually execute in browser ?

How JavaScript is actually execute in browser ?

It will help you to understand complex and core concept of JavaScript runtime which would be useful to build any web application.

ยท

5 min read

Why it is important to understand ?

To build any application using some programming language, first you need to understand how that particular language is actually work or even execute the code.

When I started to build web applications, I faced a lot of problems as JavaScript execution is way different than other programming languages. For that reason, I decided to write this to guide developers who just started.

๐Ÿ“š Prerequisites

We are using some JavaScript code for understanding and examples and so for that you require to have some basic knowledge for JavaScript. Use below link to learn about basics of JavaScript.

Basics of JavaScript

Stack

It is a simple data structure. LIFO(Last in first out) is a concept used for stack. It means last element added by user is the first one which user have to remove. Below is the representation on how stack works.

stack-operations-in-c.gif

Queue

This is similar to Array but only delete the element operation is different. When you add element to queue it will add to last and if you remove (which is also called Dequeue) then it will remove it from the start or first index. That is why it follow FIFO (First in first out) concept. It maintain two pointers which are front and rear. The front pointer always point the starting index of array and rear will point last added element.

queue-operations.gif

How JavaScript is different from other programming languages ?

JavaScript is a single-threaded non-blocking asynchronous concurrent language.It execute differently than other languages. The reason is that JavaScript is used in browser as it had to modify and execute code differently.

Now, let's understand each and every word to understand JavaScript runtime behavior.

What is Single-threaded ?

It means it only has one stack to track where we are in the program. You can say one thread means one callstack means one thing at a time.

CallStack is a data structure which keep track of where we are in the program. Suppose if we call the function we push into stack and we return from the function we simply pop (remove the top element) from the stack.

Let's take below code example.

function abc(){
console.log("Hello Reader");
}

function x(){
abc();
}

x()

Now, let's understand how JavaScript track via callstack. First, this will run main function which represent the above code's file. After that, it will call x function and again it will call abc function which ultimately print "Hello Reader" in console. After execution, these functions will be pop out from stack.

Untitled2.png

What is non-blocking and asynchronous mean ?

First, understand what is blocking. Blocking means execute in synchronous way (Line by Line execution). If JavaScript is blocking and synchronous then it will create below problems.

  • If one request is running, then user cannot do other processing. It has to wait until pending request is complete.
  • It makes browser experience very slow.

That is why, JavaScript is Non-blocking asynchronous language. It means it can execute code while other request is running. But previously we show that JavaScript do one thing at a time . So how it could do that ?

Let's clear the confusion.

Keep in mind that JavaScript runtime only contains one callstack for execution context and one heap for data storage. Below is representation of JavaScript runtime.

jsruntime.png

But, browser is more than just JavaScript runtime. It contains WebAPIs, event loop and callback queue.

browserruntime.png

Now, let's understand how it archive concurrent and asynchronous behavior using WebAPIs, event loop and callback queue.

  • WebAPIs : While running a program if any API comes then it simply push to WebAPIs area where it complete its execution and main stack continue with next line.
  • Callback Queue : When WebAPIs complete its task then it push your callback to callback queue.
  • Event Loop : It simply check if stack is empty then push first thing from callback queue to stack where it simply run it. Moreover, remember that event loop will wait until stack is empty then push callback from callback queue.

Examples for more understanding

  1. Consider below code.
console.log("before timeout") 

setTimeout(function cb(){
console.log("Printed by cb")
},0) // or 5000 no difference

console.log("After timeout");

Here, first it will execute 'before timeout' and when settimeout comes it will send it to WebAPIs and from that it will send callback function (here its cb) to callback queue. Now, event loop check whether stack is empty or not but in this case last console function remains so first it will execute that and then cb() function push into stack from callback queue. That's why we will get below output.

#Output:
#before timeout
#After timeout
#Printed by cb

You can check code execution via below website.

Execution Environment for JavaScript runtime

How to simplify code from this complex execution ?

There are two ways in which you could deal with APIs and remove this asynchronous complexity.

1.With the help of Promise chaining. Promises are new way to deal with async code. Consider below code.

getDocs(collection(db, "user")).then((snapshot) => {
      snapshot.forEach((doc) => console.log(`${doc.id} without async => ${JSON.stringify(doc.data())}`))
    })

# Fetch API => getDocs(collection(db, "user")) or fetch("url") all works same way

Here, when getDocs API fetched data after that then block will execute and print all fetched documents. As you can see you can add multiple then block which execute synchronous way.

2.With the help of Async Await. I would personally consider this as it is easy to understand and implement.

An async function is a function that knows how to expect the possibility of the await keyword being used to invoke asynchronous code. The advantage of an async function only becomes apparent when you combine it with the await keyword.

await can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.

const defaultAsync = async () => {
      const querySnapshot = await getDocs(collection(db, "user"));
      console.log("Ready")
      querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
      });

    }

In this function, it will wait until getDocs fetch its data, before that it will not print 'Ready'. By using assigned variable you could print all data which return by getDocs promise.


Thank you for reading the blog. I hope it will help you to understand the JavaScript behavior. Follow for more blogs regarding Web Development.

ย