DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

Mastering Asynchronous JavaScript: Callbacks, Promises, and Async/Await

Understanding JavaScript Asynchronous Programming

Asynchronous programming in JavaScript is essential for handling tasks that take time, such as fetching data from an API, reading a file, or interacting with a database. It ensures that JavaScript remains non-blocking and responsive, even when executing time-consuming operations.


Synchronous vs. Asynchronous Programming

  1. Synchronous: In synchronous programming, tasks execute sequentially, one after another. Example:
   console.log("Task 1");
   console.log("Task 2");
   console.log("Task 3");
Enter fullscreen mode Exit fullscreen mode

Output:

   Task 1  
   Task 2  
   Task 3  
Enter fullscreen mode Exit fullscreen mode
  1. Asynchronous: In asynchronous programming, tasks can run concurrently. The program continues executing other tasks while waiting for the asynchronous task to complete. Example:
   console.log("Task 1");
   setTimeout(() => console.log("Task 2"), 1000);
   console.log("Task 3");
Enter fullscreen mode Exit fullscreen mode

Output:

   Task 1  
   Task 3  
   Task 2  
Enter fullscreen mode Exit fullscreen mode

Key Concepts in JavaScript Async

  1. Callbacks: Functions passed as arguments to other functions, executed after an operation is completed. Example:
   function fetchData(callback) {
     setTimeout(() => {
       console.log("Data fetched");
       callback();
     }, 1000);
   }

   fetchData(() => console.log("Callback executed"));
Enter fullscreen mode Exit fullscreen mode
  1. Promises: Represents the eventual completion or failure of an asynchronous operation.
    • States of a Promise:
      • Pending
      • Fulfilled
      • Rejected

Example:

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

   promise
     .then(result => console.log(result))
     .catch(error => console.error(error));
Enter fullscreen mode Exit fullscreen mode
  1. Async/Await: Syntactic sugar for working with promises, making asynchronous code look synchronous. Example:
   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 fetching data:", error);
     }
   }

   fetchData();
Enter fullscreen mode Exit fullscreen mode

Common Asynchronous Operations

  1. setTimeout and setInterval: Perform actions after a delay or repeatedly at intervals.
   setTimeout(() => console.log("Executed after 1 second"), 1000);
   setInterval(() => console.log("Repeats every second"), 1000);
Enter fullscreen mode Exit fullscreen mode
  1. Fetching Data with APIs: Using fetch to retrieve data asynchronously.
   fetch("https://api.example.com/data")
     .then(response => response.json())
     .then(data => console.log(data))
     .catch(error => console.error("Error:", error));
Enter fullscreen mode Exit fullscreen mode
  1. Event Listeners: Asynchronous handling of user interactions.
   document.querySelector("button").addEventListener("click", () => {
     console.log("Button clicked");
   });
Enter fullscreen mode Exit fullscreen mode

Error Handling in Async Code

  1. With Promises: Use .catch() to handle errors.
   fetch("https://api.example.com/data")
     .then(response => response.json())
     .catch(error => console.error("Error:", error));
Enter fullscreen mode Exit fullscreen mode
  1. With Async/Await: Use try-catch blocks for error handling.
   async function fetchData() {
     try {
       const data = await fetch("https://api.example.com/data");
       console.log(data);
     } catch (error) {
       console.error("Error fetching data:", error);
     }
   }
Enter fullscreen mode Exit fullscreen mode

Best Practices for Asynchronous JavaScript

  1. Avoid Callback Hell: Use promises or async/await to avoid deeply nested callbacks. Example of Callback Hell:
   asyncTask1(() => {
     asyncTask2(() => {
       asyncTask3(() => {
         console.log("Tasks complete");
       });
     });
   });
Enter fullscreen mode Exit fullscreen mode

Solution with Promises:

   asyncTask1()
     .then(() => asyncTask2())
     .then(() => asyncTask3())
     .then(() => console.log("Tasks complete"))
     .catch(error => console.error(error));
Enter fullscreen mode Exit fullscreen mode
  1. Handle Errors Gracefully:

    Always use .catch() with promises or try-catch with async/await.

  2. Optimize Performance:

    Use Promise.all() for concurrent execution of independent tasks.

   const promise1 = fetch("https://api.example.com/data1");
   const promise2 = fetch("https://api.example.com/data2");

   Promise.all([promise1, promise2])
     .then(responses => Promise.all(responses.map(res => res.json())))
     .then(data => console.log(data))
     .catch(error => console.error(error));
Enter fullscreen mode Exit fullscreen mode

Conclusion

Understanding asynchronous programming is vital for building efficient and responsive JavaScript applications. By mastering callbacks, promises, and async/await, you can write cleaner and more maintainable async code, handle errors effectively, and optimize performance for real-world applications. Embracing JavaScript async is key to modern web development.

Hi, I'm Abhay Singh Kathayat!
I am a full-stack developer with expertise in both front-end and back-end technologies. I work with a variety of programming languages and frameworks to build efficient, scalable, and user-friendly applications.
Feel free to reach out to me at my business email: kaashshorts28@gmail.com.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Cloudinary image

Video API: manage, encode, and optimize for any device, channel or network condition. Deliver branded video experiences in minutes and get deep engagement insights.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay