DEV Community

Cover image for Async/Await and Promises in JavaScript
Nishant Singh
Nishant Singh

Posted on

Async/Await and Promises in JavaScript

Understanding Async/Await and Promises in JavaScript

JavaScript’s ability to handle asynchronous operations is crucial for modern web development. Promises and async/await are two key mechanisms to manage asynchronous code effectively. This article explores these concepts, their usage, and best practices, along with examples.

What are Promises?

A Promise represents a value that may be available now, or in the future, or never. It allows developers to write asynchronous code that’s more manageable and less error-prone than traditional callbacks.

States of a Promise:

  1. Pending: The initial state, neither fulfilled nor rejected.
  2. Fulfilled: The operation completed successfully.
  3. Rejected: The operation failed.

Creating and Using Promises

Here’s an example of creating and consuming a Promise:

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true; // Simulating success or failure
      if (success) {
        resolve('Data fetched successfully!');
      } else {
        reject('Error fetching data.');
      }
    }, 1000);
  });
};

fetchData()
  .then((result) => {
    console.log(result); // Logs: Data fetched successfully!
  })
  .catch((error) => {
    console.error(error);
  });
Enter fullscreen mode Exit fullscreen mode

What is Async/Await?

Async/Await is syntactic sugar built on top of Promises, introduced in ES2017 (ES8). It allows asynchronous code to be written in a synchronous-looking manner, making it more readable and easier to debug.

Key Points:

  1. The async keyword marks a function as asynchronous.
  2. The await keyword pauses the execution of an async function until the Promise is resolved or rejected.

Using Async/Await

Here’s the same example rewritten with async/await:

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true; // Simulating success or failure
      if (success) {
        resolve('Data fetched successfully!');
      } else {
        reject('Error fetching data.');
      }
    }, 1000);
  });
};

const fetchAsyncData = async () => {
  try {
    const result = await fetchData();
    console.log(result); // Logs: Data fetched successfully!
  } catch (error) {
    console.error(error);
  }
};

fetchAsyncData();
Enter fullscreen mode Exit fullscreen mode

Comparing Promises and Async/Await

Feature Promises Async/Await
Syntax Chaining with .then and .catch Looks like synchronous code with await
Readability Moderate, especially with long chains High, especially for sequential tasks
Error Handling .catch for errors try/catch for errors
Debugging Stack traces can be challenging Easier due to synchronous-like flow

Example: Handling Multiple Promises

Both Promises and async/await can handle multiple asynchronous operations using Promise.all or loops. Here’s an example:

Using Promise.all:

const fetchData1 = () => Promise.resolve('Data 1');
const fetchData2 = () => Promise.resolve('Data 2');

Promise.all([fetchData1(), fetchData2()])
  .then((results) => {
    console.log(results); // Logs: ['Data 1', 'Data 2']
  })
  .catch((error) => {
    console.error(error);
  });
Enter fullscreen mode Exit fullscreen mode

Using Async/Await:

const fetchAsyncData = async () => {
  try {
    const results = await Promise.all([fetchData1(), fetchData2()]);
    console.log(results); // Logs: ['Data 1', 'Data 2']
  } catch (error) {
    console.error(error);
  }
};

fetchAsyncData();
Enter fullscreen mode Exit fullscreen mode

Best Practices for Async/Await and Promises

  1. Use try/catch for Error Handling:
    Always wrap await calls in try/catch blocks to handle errors gracefully.

  2. Avoid Blocking Code:
    Do not use await inside loops without careful consideration as it can lead to performance bottlenecks. Use Promise.all for parallel execution.

  3. Chain Promises Wisely:
    For simpler operations, Promises with .then and .catch may suffice. Use async/await for complex flows.

  4. Keep Functions Modular:
    Break down large functions into smaller ones to keep your async code clean and maintainable.

Conclusion

Promises and async/await are powerful tools for managing asynchronous operations in JavaScript. While Promises provide flexibility and a structured way to handle async tasks, async/await enhances readability and debugging. Understanding when and how to use them effectively will greatly improve your JavaScript development workflow.

Watch more content on our Youtube channel - Frontend With Chandel

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

Best practices for optimal infrastructure performance with Magento

Running a Magento store? Struggling with performance bottlenecks? Join us and get actionable insights and real-world strategies to keep your store fast and reliable.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️