Asynchronous JavaScript

JavaScript

readTime

4 min

Asynchronous JavaScript

If you're starting out with JavaScript and wondering how asynchronous programming works, you're in the right place.

In this article, I’ll explain what asynchronous code is, how to handle it, and why it’s so important in modern app development.

Get ready to explore the world of asynchronous programming, where you’ll learn to use callbacks, promises, and async/await in JS.


What is Synchronous Code in JavaScript?

Before diving into asynchronous programming, it’s essential to understand what synchronous code is.

In JavaScript, code is executed line by line, which means each line must complete before moving on to the next.

Synchronous Code Example

javascript
console.log("Start");
for (let i = 0; i < 1000000000; i++) {
  // Simulating a heavy operation
}
console.log("End");

In the example above, 'Start' is logged first, then the heavy operation (a for loop) runs, and finally, 'End' is logged. During the loop, the rest of the code is blocked and cannot proceed.

Problems with Synchronous Code

Synchronous code can cause issues when an operation takes longer to complete.

For instance, when downloading a large file or performing complex calculations, the user interface may freeze, preventing users from interacting with the app—a frustrating experience.

Asynchronous JavaScript

Asynchronous programming addresses these issues.

Asynchronous code allows other tasks to continue running while a long operation is in progress. This keeps the app responsive, so the user can continue using it.

JavaScript isn’t inherently asynchronous, but with mechanisms like callbacks, promises, and async/await, we can manage asynchronous operations in our applications.

Callbacks – The First Step in Asynchronous Programming

What is a Callback?

A callback is a function passed as an argument to another function, which will be called once a particular operation is completed.

This is the foundational way to handle asynchronous code in JavaScript.

Callback Example

javascript
function fetchData(callback) {
  setTimeout(() => {
    const data = "Data has been fetched";
    callback(data);
  }, 2000);
}

fetchData((result) => {
  console.log(result);
});

In this example, fetchData simulates an asynchronous data-fetching operation that takes 2 seconds. Once completed, it calls the provided callback with the result.


Callback Hell – When Callbacks Fall Short

As you start nesting multiple callbacks, you may encounter a problem known as “callback hell.”

The code becomes challenging to read and maintain.

Callback Hell Example

javascript
fetchData((data) => {
  processData(data, (processedData) => {
    saveData(processedData, () => {
      console.log("Operation completed");
    });
  });
});

This nesting leads to a “pyramid of doom,” where the code is progressively indented, making it unreadable.


Promises in JavaScript – A Modern Approach to Asynchronous Programming

To solve the callback hell problem, ES6 introduced Promises.

A Promise is an object representing the eventual outcome of an asynchronous operation. It allows for cleaner, more maintainable code.

Creating a Promise

javascript
const promise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve("Operation successful");
  } else {
    reject("Operation failed");
  }
});

A Promise can be in one of three states:

  • Pending
  • Fulfilled
  • Rejected

Handling Promises with then() and catch()

To handle the outcome of a Promise, we use the then() and catch() methods.

Promise Handling Example

javascript
promise
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  });
  • then() is called when the Promise is fulfilled.
  • catch() is called when the Promise is rejected.

Async/Await – A New Way to Write Asynchronous Code

Async/Await is a modern way to write asynchronous code that looks synchronous.

This makes code easier to read and write, eliminating the need for multiple then() calls.

Async Function

To use await, a function must be marked as async.

Async/Await Example

javascript
async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("Error:", error);
  }
}

fetchData();

In this example, the async function fetchData fetches data from an API and logs it.

Error Handling with Async/Await

With async/await, error handling is done using a try...catch block.

Error Handling Example

javascript
async function processData() {
  try {
    const data = await fetchDataFromServer();
    // Process data
  } catch (error) {
    console.error("An error occurred:", error);
  }
}

If the asynchronous operation fails, the error is caught in the catch block.

Event Loop – How JavaScript Manages Asynchronous Code

To understand how JavaScript executes asynchronous code, we need to learn about the Event Loop.

How the Event Loop Works

JavaScript is single-threaded, but the Event Loop allows it to handle asynchronous operations.

  • Call Stack – a stack of function calls.
  • Callback Queue – a queue of functions waiting to be executed.
  • Event Loop – a mechanism that moves functions from the Callback Queue to the Call Stack when it’s empty.

This ensures asynchronous code doesn’t block the app’s execution.

Asynchronous Programming in Node.js

Node.js is a JavaScript runtime that allows JavaScript to run outside the browser.

Asynchronous File Reading Example

javascript
const fs = require("fs");

fs.readFile("file.txt", "utf8", (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});

console.log("File reading initiated");

In this example, Node.js reads the file content asynchronously, without blocking the rest of the code.

Summary

Asynchronous programming in JavaScript is essential for building efficient, interactive applications.

By understanding callbacks, promises, and async/await, you can effectively handle asynchronous code in your projects.

Remember, JavaScript is one of the most popular languages for web development, and mastering asynchronous programming is vital for any developer.

authorImg

Witek Pruchnicki

I passionately share knowledge about programming and more in various ways.