Demystifying Asynchronous JavaScript: A Step-by-Step Guide

Demystifying Asynchronous JavaScript: A Step-by-Step Guide

Taking Your Web Development Skills to the Next Level with Asynchronous JavaScript.

Introduction

Before delving into the topic of asynchronous JavaScript, it is assumed that the reader has a basic understanding of JavaScript. As a popular programming language, JavaScript is widely used for creating dynamic and interactive web pages. It is a high-level, interpreted language that runs on web browsers and enables developers to add interactivity to websites.

To fully comprehend asynchronous JavaScript, it is recommended that one should be familiar with the basic concepts of JavaScript such as variables, data types, functions, loops, and conditional statements. Additionally, in the coming blogs, we will be understanding the concept of callbacks, promises, error handlings and many more. With these prerequisites in mind, one can proceed to learn about asynchronous JavaScript and how it can be used to optimize the performance of web applications.

Synchronous JavaScript

Imagine that you are in the year 2005, on a bright and sunny day, and you find yourself stuck in a queue waiting to purchase a bus ticket. Despite there being approximately 100 people ahead of you in the queue, you are unable to bypass them due to the rule requiring you to wait in the queue in a one-after-another fashion. As a result, you must wait for hours to purchase your ticket, leaving you with no other option than to patiently stand in line.

This scenario can be compared to the concept of synchronous JavaScript, where a function may take some time to execute and other functions that are waiting to execute must remain idle until the previous function has been completed. This sequential execution can lead to slower performance and may cause applications to become unresponsive, much like the sluggishness experienced while waiting in a long queue.

Let's write the logic for the same scenario of 2005 where we were not allowed to bypass the people in a queue.


const climaticCondition = "Sunny";
const activityOfMine = "Queue for ticket";
const thingsRunningInMyMind = "I wish I could bypass them without really being in a queue";
const totalPeopleInAQueue = 10;
let byPassed = 0;

console.log(`Climate is very ${climaticCondition} and I am in a ${activityOfMine}. ${thingsRunningInMyMind}`)
for (let i = 0; i < totalPeopleInAQueue; i++){

    byPassed++;
    console.log(`By passed ${byPassed}`);
}

console.log("Finally task is done");

Asynchronous JavaScript

Previously we were in 2005 now let's time travel to the future and go to 2023. In 2023, with the advancement of technology, people no longer have to wait in long queues to buy a bus ticket. Instead, they can book their tickets online through various digital channels like mobile banking, internet booking, or UPI systems. This means that the process of buying a ticket, which was previously a single, monolithic task, has now been broken down into smaller, more manageable parts that can be executed concurrently.

Similarly, in asynchronous JavaScript, instead of executing functions one after the other, like waiting in a queue, multiple tasks can be executed simultaneously. This allows the program to run more efficiently and complete tasks faster, much like how people can now book bus tickets faster and more efficiently through various digital channels.

Furthermore, with the use of modern technologies like web workers and promises, asynchronous JavaScript can be utilized to perform complex tasks in the background, without blocking the main thread and hindering the user experience. This is similar to how people can now book bus tickets in the background while performing other tasks, without the need to wait in long queues or waste time.

Overall, the scenario of buying bus tickets in 2023 highlights how breaking down complex tasks into smaller, manageable parts can lead to more efficient and faster execution, much like how asynchronous JavaScript can be used to execute multiple tasks simultaneously for better performance and user experience.

// Power of Internet and Mobile banking.
console.log("Getting Bus ticket")
const personFirst = "I am in a queue for 1 hour and I will get the ticket first.";
const personSecond = "I will use mobile banking and internet to buy a ticket"

setTimeout(()=>{
    console.log("I am the first person")
    console.log("I am still in a queue.")
},4000);

console.log("I am the second person and I got my ticket in just few minutes.");

In the above code, the line of code which is, at last, executes first. This is the power of asynchronous JavaScript. In our example, the second person who is not even in a queue gets the bus ticket first. The other person was in a queue for more than an hour but the person doesn't get the ticket as soon as the second person gets.

Event Handler

Asynchronous programming means that instead of waiting for a long-running task to complete before moving on to the next task, the program can keep running and notify us when the task is done.

Event handlers are a type of asynchronous programming. You provide a function (the event handler) that will be called, not right away, but whenever the event happens. For example, if "the event" is "the asynchronous operation has completed", then that event could be used to notify the caller about the result of an asynchronous function call.

An example of using event handlers is the XMLHttpRequest API, which is used to make HTTP requests to a remote server using JavaScript. Since this can take a long time, it's an asynchronous API, and you get notified about the progress and eventual completion of a request by attaching event listeners to the XMLHttpRequest object.

When we attach an event listener to the XMLHttpRequest object, our program can continue to run while the request is going on, and our event handler will be called when the request is complete. This allows us to perform other tasks while we wait for the request to complete, which can make our programs more efficient.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Asynchronous JS Example</title>
</head>

<body>

    <button id="request">Click here to start request</button>
    <button id="reload">Reload</button>
    <pre class="event"></pre>

    <script>

        const event_log = document.querySelector('.event');

        document.querySelector('#request').addEventListener('click', () => {
            event_log.textContent = '';

            const xmlHttpRequest = new XMLHttpRequest();

            xmlHttpRequest.addEventListener('loadend', () => {
                event_log.textContent = `${event_log.textContent} Status after completion: ${xmlHttpRequest.status}\n`;

            });
            // takes time to request
            xmlHttpRequest.open('GET', 'https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json');

            xmlHttpRequest.send();
            // runs first
            event_log.textContent = `${event_log.textContent} Started XMLHTTPRequest\n`;
        });

        document.querySelector('#reload').addEventListener('click', () => {
            event_log.textContent = '';
            document.location.reload();
        })
    </script>
</body>

</html>

In the code you provided, the last statement appears to run first because it is executed before the XMLHTTPRequest has completed.

When you click the "Click here to start request" button, the event listener fires and the XMLHttpRequest object is created and sent. However, since the request takes some time to complete, the code after the send() method (which logs the "Started XMLHTTPRequest" message) will be executed before the request is finished and the loadend event is triggered.

Once the request is complete and the loadend event is triggered, the event listener's callback function is executed, and the message containing the status code is appended to the event_log element, which replaces the previous message.

So, although the "Started XMLHTTPRequest" message appears to be the last statement in the code, it is actually executed before the completion of the request, and the message containing the status code is added to the event_log element after the request has completed.

Thank you

In the next blog post, we will delve into a few important concepts related to asynchronous programming, namely callbacks, promises, async/await, and try/catch. These are widely used techniques in modern JavaScript programming to manage asynchronous tasks, handle errors, and improve the performance of our code.

Reference: