Callback Functions, Event Listeners, and Event Loop in JavaScript.

How is Event Loop responsible for asynchronous programming in JS?

Callback Functions,  Event Listeners, and Event Loop in JavaScript.

Hello Readers, hope you're doing good. In this blog, we will try to understand the concept of Event loop which makes JavaScript asynchronous (remember that JS is a synchronous, single-threaded language). Before jumping to the event loop, you should have a clear understanding of callback functions and event listeners.

We'll follow the below-mentioned roadmap in our journey:-

  1. Callback Functions
  2. Event Listeners and Related Scenarios
  3. Event Loop, Callback Queue, and Microtask Queue

Callback Functions and Asynchronous Programming

In JavaScript, functions are known as First-Class Citizens because they allow us to perform asynchronous tasks. Functions can also be used as an argument inside a function and can be returned as well. But what exactly is a callback function? When we pass a function(let's say Y) inside another function (let's say X), Y is known as a Callback function.

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

setTimeout(function(){
    console.log("Print this after 2 seconds");
},2000);
function X(Y)
{
    console.log("I am X");
    Y();
}
X(function Y()
{
    console.log("I am Y");
})

Consider the above code snippet. Function Y is named the Callback function because its execution is controlled by function X, and it can be called instantly or at a later point in time. I have also introduced a setTimeout function in the above code to make you aware of the power of callbacks. So when we try to execute the above code line by line (from top to bottom), a callback function is passed to the setTimeout function as its first parameter, and it also attaches a timer of a specified duration(passed as the second parameter).

  • Since JS is a synchronous language, it won't wait for the setTimeout function to execute and proceeds to the next line.
  • Function X is defined and invoked by passing function Y as an argument. Now I am X is printed in the console.
  • Function Y is also invoked inside X and I am Y is printed in the console.
  • After 2 seconds, the timer attached to the setTimeout function gets expired and the callback function is executed, printing Print this after 2 seconds in the console.

It is important to note that asynchronous programming in JS is not possible without Web APIs(like setTimeout()) and callback functions.

Now that we have gained some insights about callback functions, we can now move on to the next section, i.e Event Listeners.

Event listeners are among the most frequently used JavaScript structures in web design. They allow us to add interactive functionality to HTML elements by “listening” to different events that take place on the page, such as when the user clicks a button, presses a key, or when an element loads.

let bb=50;
function addEventListeners()
{
    let a=5;
    document.getElementById("btn").addEventListener("click",function xyz(){
        let b=10;
        console.log("Button Clicked",++a);
        console.log("Inside b",++b);
        console.log(bb);
    })
}
addEventListeners();

Look at the above code snippet. Here, I've attached an event listener to click event of a button (with id - btn ). It's important for us to know that Event listeners are a part of Web APIs(DOM APIs in specific) and not JavaScript. Look at below image:

image.png

Before the code is executed, 2 separate memories/scope are created : Script for let variable and global scope(pointed by window object). Look how addEventListener is stored inside global memory.

Now let's track the execution of this program:-

  1. When the button (with id: btn) is clicked, the callback function XYZ gets executed.
  2. At this point in time, addEventListeners function is pushed into the call stack and xyz forms Closure with its lexical environment.

image.png

image.png

And we can clearly see that the event listener has access to 3 scopes(Global, Script, and Closure). We won't be covering Closures in this blog but the basic idea is that the closures are used for data hiding/abstraction in JavaScript.

  1. So function XYZ can access a due to closure(lexical scope), bb due to scope chaining, and b due to its local scope.
  2. Final output would be:-
    Button Clicked 6
    Inside b 11
    50

Hope you've understood everything till now. So general practice is to remove these heavy event listeners and perform garbage collection. This is done to improve the performance of the web page (Event listeners occupy the memory even when the call stack is empty, thus leading to slow loading and interactivity).

Event Loop in JavaScript

In this section, we will learn about the event loop, callback queue, and microtask queue.

image.png

As we know that JS is a synchronous, single threaded language i.e a single task could be executed in the call stack at a given point in time.

Time, Tide, and JavaScript wait for none.

So in order to execute functions like setTimeout, a callback queue is maintained in the browser. Initially, the callback function is stored inside global space(window object). And when the timer expires, this callback function is moved to the callback queue, so that it could be passed to the call stack. Let's understand this with an example:

console.log("Start");

setTimeout(()=>{
    console.log("I'll be printed in the last line");
},1000);

const getData=()=>{
    fetch("https://cat-fact.herokuapp.com/facts")
    .then(res=>res.json())
    .then((jsondata)=>{
        console.log(jsondata);
    })
}
getData();
console.log("End");

In the above code snippet, a global execution context will be created and pushed to call stack.

  • JS engine will use console API provided by the browser and prints Start in the console.
  • Now it encounters the setTimeout function, so the callback function is stored inside web API and a timer of 1000ms is attached to it.
  • Then a function getData is defined which in turn is using the fetch API of the browser to make a fetch call. -getData is executed and the callback function inside fetch is moved to Web API. Now it will wait for the endpoint to respond.

Now comes the tricky and amusing part!! As soon as this promise is resolved, the CB function inside fetch is not moved to the callback queue, but it is moved to Microtask Queue.

  • Microtask Queue is also known as priority queue because at a given point in time, if there are callback functions inside both callback and microtask queue, CB function inside microtask queue is prioritized by event loop(to push into the call stack for execution).

-Suppose the promise is resolved quickly(before the timer in the setTimeout function is expired), in this case, data returned by fetch call will get displayed in the console and then the CB function inside setTimeout is executed.

Start
End
(5) [{…}, {…}, {…}, {…}, {…}]
I'll be printed in the last line

So the task of the event loop is to continuously monitor the call stack, callback queue, and microtask queue. When the Call stack is empty, the Event loop pushes the callback functions from the callback/microtask queue based on availability and priority.

If a promise takes a longer time to resolve compared to the timer attached to a setTimeout function, then it won't be pushed to the microtask queue until it gets a response from the server, and as a result, the CB function inside the callback queue will get a chance to get executed first.

All the callback functions which come through promises will go inside Microtask Queue. CB functions that are invoked based on Mutation Observer API(used to monitor any changes inside DOM tree) are also placed inside Microtask Queue.

And this is how Event Loop is responsible for asynchronous programming in JS.

THE END!

In this blog, we have learned about callback functions, event listeners, and event loop in detail. You can also read more on developer.mozilla.org/en-US/docs/Web/JavaSc..

Reference: youtube.com/watch?v=8zKuNo4ay8E

Thanks for reading and have a good day.