Asynchronous vs. Synchronous Calls in JavaScript: Understanding the Difference

Asynchronous vs. Synchronous Calls in JavaScript: Understanding the Difference

·

4 min read

Introduction

In JavaScript, asynchronous and synchronous calls refer to different ways of executing code and handling operations. Understanding these concepts is crucial for developing efficient and responsive JavaScript applications.

Synchronous Calls in JS

Synchronous calls, also known as blocking calls, execute one operation at a time, waiting for each operation to complete before moving on to the next. When a synchronous call is made, the program waits for that operation to complete before moving on to the next line of code. This means that the execution of code is halted until the current operation is finished. Synchronous calls can be useful when you need to ensure that certain operations are completed in a specific order.

Example of Synchronous calls

function abc(){
    console.log("we are inside function");
}

console.log("start");
abc();
console.log("end");

Output:

Stack Representation of Synchronous Calls

Asynchronous Calls

Asynchronous calls, also known as non-blocking calls, allow the program to continue executing other operations without waiting for the current operation to finish. Asynchronous operations are typically used for tasks that may take some time, such as fetching data from a server, reading a file, or waiting for user input. Instead of blocking the execution, asynchronous calls initiate the operation and provide a callback function to handle the result once it becomes available.

Example of Asynchronous calls

console.log("Start");
setTimeout(() => {
    console.log("we are in settimeout");
})
console.log("End");

Output:

Stack Representation of Asynchronous Calls

Where Asynchronous JS is used ?

console.log("start");

function login(email, pass) {
  setTimeout(() => {
    console.log("now we have data");
    return { rating: 3 };
  }, 3000);
}

const userRating = login("abc@gmail.com", 1234567890);
console.log(userRating);

console.log("end");

In the given scenario, the client needs to retrieve data from the server using the login function. However, due to the uncertainty of the server's response time, a setTimeout function is employed to introduce a delay of 3 seconds. Consequently, the login function is called to fetch the data and store it in the variable userRating. Nevertheless, when attempting to log userRating to the console, it displays as undefined. This unexpected outcome can be attributed to the asynchronous nature of the setTimeout function, which pushes the subsequent statement to the Web APIs queue and allows it to proceed. As a result, the console.log statement is executed before the server response is received, leading to the undefined value of userRating.

To overcome this problem callback function is used

console.log("start");

function login(email, pass, callback) {
  setTimeout(() => {
    console.log("now we have data");
    callback({ rating: 3 });
  }, 3000);
}

const userRating = login("abc@gmail.com", 1234567890, (user) => {
  console.log(user);
});
console.log(userRating);

console.log("end");

Understanding the Event Loop

The event loop is a fundamental concept in JavaScript that enables asynchronous behavior. It continuously checks the call stack and task queue, ensuring that the tasks are executed in the correct order. The event loop allows JavaScript to perform non-blocking operations, improving the overall performance of applications.

  • Callbacks

Callbacks are a traditional approach to handling asynchronous operations in JavaScript. A callback is a function that gets executed after a certain task is completed. Here's how to use callback functions:

function fetchData(callback) {
  // Simulating an asynchronous operation
  setTimeout(function () {
    const data = "Some data";
    callback(data);
  }, 2000);
  console.log("Data received");
  //but in actual, data is not received
  //it will be received after 2 seconds
}

function processData(data) {
  console.log("Data:", data);
}

fetchData(processData);

Output:

  • Promises

Promises provide a more structured and flexible way of handling asynchronous operations. A promise represents the eventual completion or failure of an asynchronous task. Here's an example of using promises:

function fetchData() {
  return new Promise(function(resolve, reject) {
    // Simulating an asynchronous operation
    setTimeout(function() {
      const data = 'Some data';
      resolve(data);
    }, 2000);
    console.log("Data received");
  });
}

fetchData()
  .then(function(data) {
    console.log('Data:', data);
  })
  .catch(function(error) {
    console.error('Error:', error);
  });

Output:

  • Async/Await

Async/await is a modern approach introduced in ECMAScript 2017 for writing synchronous-like code that handles asynchronous operations. It provides a more readable and concise syntax. Here's an example:

async function fetchData() {
    return new Promise(function(resolve, reject) {
    // Simulating an asynchronous operation
    setTimeout(function() {
      const data = 'Some data';
      resolve(data);
    }, 2000);
  });
}

async function processData() {
  try {
    const data = await fetchData();
    console.log('Data:', data);
  } catch (error) {
    console.error('Error:', error);
  }
}

processData();

Output:

Synchronous Implementation with Async/Await:

function fetchData() {
  return new Promise(function(resolve, reject) {
    // Fetch data from an API asynchronously
    fetch('https://gorest.co.in/public/v2/users')
      .then(function(response) {
        resolve(response.json());
      })
      .catch(function(error) {
        reject(error);
      });
  });
}

fetchData()
  .then(function(data) {
    // Display the data
    console.log(data);
  })
  .catch(function(error) {
    console.error('Error:', error);
  });

Output:

Youtube Video

Conclusion

Asynchronous and synchronous calls play a vital role in JavaScript programming. By understanding and effectively utilizing techniques like callback functions, promises, and async/await, developers can handle asynchronous operations efficiently. Additionally, comprehending the event loop and writing non-blocking code enhances the performance and responsiveness of JavaScript applications. Mastering these concepts empowers developers to create robust and user-friendly web experiences.

Did you find this article valuable?

Support Yash Nilesh Brid by becoming a sponsor. Any amount is appreciated!