How does Javascript work? What exactly is an event loop?

renu ganvir
5 min readFeb 6, 2023

When building an app or a website, we mainly use JavaScript as a base language. I frequently need to integrate APIs into websites I’m building and use Web APIs like setTimeout, fetch, cookie store, and many others; I hope you do too.

We must know a very small but crucial fact: Javascript is a synchronous, single-threaded language, which means that only one piece of code can be executed at a time, sequentially. You must be wondering, then, how Javascript can perform asynchronous operations if it is a synchronous language. Call stack, callback queue, microtask queue, and event loop are the main concepts used by the browser to make this work. Wondering what all these are in JS???🤔

Let us understand all of these with example.

Call Stack

The primary function of the call stack is to run one piece of code at a time, therefore anything contained therein is executed without any context.

A global execution context (GEC) is created whenever any Javascript code has to run, and on top of that, code is executed. JavaScript cannot execute any code without GEC.

Step1: logs ‘First line’
from line 2–4 function declaration is stored and allocated a memory.(during Hoisting)
Step 2: greet function is invoked; at this point execution context is created for ‘greet()’. And line by line code is executed.
Then it logs ‘Hello! world’
Step 3: it logs ‘End line’
Step 4: control moves and sees for any line of code to be executed and finds nothing and hence GEC also pops from call stack.

Fig 1: How synchronous code works?

No doubt the above code and execution cycle is synchronous.

Let’s go on to the next level. What if we want to set up a timer⏰ and once the timer expires, we want to run a certain code? Basically an asynchronous code.🤔

You must have guessed the output just by reading this code 😃 ; now let’s see how it works.

Step 1: logs ‘First line’
Step 2: controls move to setTimeout, greetCallback() is then get registered and starts its timer, minimum of 10000ms.

Note: timer set in setTimeout is never precise, it is never guaranteed that callback will run at the specific time that is set. Definitely, callback may take longer than the time set, for execution.

Step 3: (Still, the timer is not over.) control reaches line 5, logs ‘Last line’.
Step 4: nothing to execute in the next line and hence GEC also pops out from call stack.

Post 10000ms → timer expires

Step 5: We are left with greetCallback for execution, greetCallback() was registered with web APIs, however, it cannot be put directly into the call stack to run the code.

When the timer ends, first and foremost, the registered callback moves to the callback queue.
Step 6: Event loop check if any callback is present in callback queue, if yes, then it moves the callback to the call stack for execution.

Fig 2: how setTimeout works?

Callback queue

Callbacks from web APIs will get pushed into the callback queue and wait for their turn for execution. Some web APIs examples are setInterval, clearTimeout, DOM APIs, etc.

Event loop:

The event loop is the master caretaker or manager of the javascript engine and decides which section or part of code will run first. It monitors and manage the call stack, the callback queue, and microtask queue.

In our example, when greetCallback moves to the callback queue, the event loop first checks if any code needs to run; if yes, it then also checks if the call stack is empty or not. Once the event loop confirms the call stack is empty, it first pushes GEC in call stack.

Next, the event loop dequeues callback from callback queue and pushes code into the call stack for execution.
The event loop examines the callback queue one more time but finds nothing; and hence GEC is popped out at the end.

Till the timer is okay, but we also use fetch web API very frequently to interact with a server. Now let’s look at an example where we would need to use both the timer and fetch web API.

Let’s look at the log first.

Fig: 3 How fetch and setTimeout works?

In this example, we see fetch and setTimeout, which are both registered in web APIs. However, fetch callback moves to microtask queue and once the timer expires, setTimeout callback moves to callback queue.

When the event loop checks, it first looks for callbacks in the microtask queue, which has a higher priority than the callback queue. As we can see in Fig. 3, the event loop first pushes the callback from the microtask queue to the call stack for execution.
Once all callbacks are completed from microtask queue, event loop then checks callback queue, if any piece of code needs to execute. If yes, it pushes all callbacks one by one from the callback queue to the call stack for execution.

Microtask Queue

Microtask queue contains all the web APIs that are blocking in nature. Which means the main thread gets blocked for a certain time, till all blocking callback gets executed. Some blocking web APIs are Promise, IntersectionObserver, MutationObserver, etc.

Note: Callbacks in the callback queue can also go into starvation if callbacks keep on queuing forever in the microtask queue.

This is how execution happens in javascript.

--

--