DEV Community

DevFrontier
DevFrontier

Posted on • Edited on

Difference of using async / await vs promises?

Both async/await and Promises are ways to handle asynchronous operations in JavaScript. Here’s a breakdown of their differences, advantages, and use cases:

Promises

Definition: A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value.

Syntax:

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Data fetched");
    }, 1000);
  });
};

fetchData()
  .then((data) => console.log(data))
  .catch((error) => console.error(error));
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • Use .then() to handle success.
  • Use .catch() to handle errors.

  • Can chain multiple asynchronous operations using .then().

Advantages:

  • Better than callback hell (.then() chaining is cleaner than nested callbacks).
  • Explicit error handling with .catch().

Challenges:

  • Chaining can still become hard to read when dealing with many Promises (known as "Promise hell").
  • Error handling might require extra care when chaining multiple .then() calls.

Async/Await

Definition: async/await is a syntactic sugar built on top of Promises, making asynchronous code look and behave more like synchronous code.

Syntax:

const fetchData = async () => {
  try {
    const data = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("Data fetched");
      }, 1000);
    });
    console.log(data);
  } catch (error) {
    console.error(error);
  }
};

fetchData();
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • Use the async keyword to declare a function that returns a Promise.
  • Use await to pause the execution until the Promise is resolved.
  • Handle errors using try...catch.

Advantages:

  • Code readability: The syntax is cleaner and easier to understand compared to .then() chaining.
  • Easier to debug: Debugging tools allow you to step through async/await code just like synchronous code.
  • Works great with try...catch for centralized error handling.

Challenges:

  • Must be used inside functions declared with async.
  • Can sometimes lead to blocking behavior if not properly handled in loops or sequential asynchronous calls.


When to Use
Promises:

  • For simple, one-off asynchronous operations.
  • When working with libraries or APIs already designed around Promises.
  • When chaining multiple unrelated operations.

Async/Await:

  • For complex workflows with multiple dependent asynchronous operations.
  • When you want cleaner, more readable code.

- When debugging is crucial.

Combining Both
You can combine async/await with Promises for advanced use cases:

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Data fetched"), 1000);
  });
};

const processData = async () => {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
};

processData();
Enter fullscreen mode Exit fullscreen mode

Here’s a real-world scenario that shows when you might use Promises vs Async/Await:

Scenario: Fetching User Data and Posts

Imagine you’re building a dashboard that needs:

  1. The user profile information.
  2. The user’s latest posts.
  3. Both should be fetched from APIs.

Using Promises

function loadDashboard() {
  getUser()
    .then(user => {
      console.log('User:', user);
      return getPosts(user.id);
    })
    .then(posts => {
      console.log('Posts:', posts);
    })
    .catch(error => console.error(error));
}

Enter fullscreen mode Exit fullscreen mode
  • The second API call (getPosts) waits for the first (getUser).
  • Uses .then() chaining for sequential logic.

Using Async/Await

async function loadDashboard() {
  try {
    const user = await getUser();
    console.log('User:', user);

    const posts = await getPosts(user.id);
    console.log('Posts:', posts);
  } catch (error) {
    console.error(error);
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Same logic but more readable and synchronous-looking.
  • Easier to handle errors with try...catch.

Running in Parallel (Best Practice)

If the two calls are independent (say, you also need comments at the same time), you can run them concurrently:

async function loadDashboard() {
  try {
    const [user, posts, comments] = await Promise.all([
      getUser(),
      getPosts(),
      getComments()
    ]);
    console.log(user, posts, comments);
  } catch (error) {
    console.error(error);
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)