DEV Community

Cover image for Callbacks, Async/Await, Promises - JavaScript
Muhammad Shakir
Muhammad Shakir

Posted on • Edited on

Callbacks, Async/Await, Promises - JavaScript

Asynchronous JavaScript is a fundamental concept in modern web development. It helps developers create responsive and efficient applications. Concepts like callbacks, promises, and async/await are useful for handling complex tasks and ensuring a smooth user experience.

What is Asynchronous Javascript?

Asynchronous JavaScript is a programming paradigm that deals with concurrent task handling without blocking the main execution thread. This is particularly important in web development, where tasks like fetching data from a server, handling user interactions, and managing animations often require waiting for certain tasks to be completed. Instead of waiting for other tasks to complete first before proceeding, asynchronous programming enables developers to work with tasks concurrently. To illustrate this, let's consider a scenario from our daily lives.

Scenario: Doing Laundry

When doing laundry, you load the washing machine and start it. While the machine washes your clothes, you're free to do other tasks like cleaning or working. The washing machine operates asynchronously, freeing you from having to wait for each cycle to finish before moving on.

Now, let's explore its coding implementation.

Using Callbacks

// Washing clothes
function washClothes(callback) {
  console.log("Washing Clothes...");
  setTimeout(function () {
    console.log("Washing completed.");
    callback();
  }, 2000); // takes 2 seconds for washing
  console.log("While the machine is washing, let's handle some other tasks.");
}

// Drying clothes
function dryClothes(callback) {
  console.log("Drying Clothes...");
  setTimeout(function () {
    console.log("Drying completed.");
    callback();
  }, 1500); // takes 1.5 seconds for drying
  console.log("While the machine is drying clothes, let's handle some other tasks.");
}

function foldClothes() {
  console.log("Folding clothes...");
}

// Doing laundry using callbacks
washClothes(function() {
  dryClothes(function() {
    foldClothes();
  });
});
Enter fullscreen mode Exit fullscreen mode

The output will be as follows:

Washing Clothes...
While the machine is washing, let's handle some other tasks.
Washing completed.
Drying Clothes...
While the machine is drying clothes, let's handle some other tasks.
Drying completed.
Folding clothes...

While the asynchronous approach is efficient, managing nested callbacks can lead to a callback hell. To address this, we can utilize the concept of promises. Let's delve into promises in the next section:

Doing Laundry using Promises:

Promises are a structured way to handle asynchronous operations. They represent a value that might be available now, in the future, or never. Promises can be in one of three states:

  1. pending
  2. fulfilled
  3. rejected. They allow chaining of operations and help avoid the callback hell issue.

Coding Scenario

function washClothes() {
  return new Promise(function(resolve) {
    console.log("Washing clothes...");
    setTimeout(function() {
      console.log("Washing completed.");
      resolve();
    }, 2000);
  });
}

function dryClothes() {
  return new Promise(function(resolve) {
    console.log("Drying clothes...");
    setTimeout(function() {
      console.log("Drying completed.");
      resolve();
    }, 1500);
  });
}

function foldClothes() {
  console.log("Folding clothes...");
}

washClothes()
  .then(function() {
    return dryClothes();
  })
  .then(function() {
    foldClothes();
  });
Enter fullscreen mode Exit fullscreen mode

Output:

Washing clothes...
Washing completed.
Drying clothes...
Drying completed.
Folding clothes...

Using promises, we've eliminated callback hell and created a cleaner, more readable structure.

Now, let's simplify it further using async/await.

Async/Await

Async/await is a modern approach to handling asynchronous operations in a more synchronous-like fashion. It uses the async keyword to define an asynchronous function and the await keyword to pause the execution of the function until the awaited promise is resolved. This makes asynchronous code look similar to synchronous code, improving readability and maintainability.

Doing Laundry using async/await

Let's use async/await to further simplify the code, making it appear almost synchronous.

function washClothes() {
  return new Promise(function(resolve) {
    console.log("Washing clothes...");
    setTimeout(function() {
      console.log("Washing completed.");
      resolve();
    }, 2000);
  });
}

function dryClothes() {
  return new Promise(function(resolve) {
    console.log("Drying clothes...");
    setTimeout(function() {
      console.log("Drying completed.");
      resolve();
    }, 1500);
  });
}

function foldClothes() {
  console.log("Folding clothes...");
}

(async function() {
  await washClothes();
  await dryClothes();
  foldClothes();
})();
Enter fullscreen mode Exit fullscreen mode

Output:

Washing clothes...
Washing completed.
Drying clothes...
Drying completed.
Folding clothes...

Summary:
Asynchronous JavaScript mechanisms like callbacks, promises, and async/await are essential tools for managing non-blocking operations and improving the efficiency and responsiveness of web applications. They allow developers to write code that can handle multiple tasks concurrently without freezing the main thread.

Top comments (0)