Promises vs async await and scenarios of uses

In JavaScript, both async/await and Promise are used to handle asynchronous operations. However, they differ in terms of syntax, readability, and error handling. Let's explore the differences between async/await and Promise with examples and explanations:

  1. Syntax:
  • Promise: Promises use a chainable syntax with .then() and .catch() methods to handle asynchronous operations. It involves creating a promise object and attaching callbacks to it.
function fetchUser() {
  return new Promise((resolve, reject) => {
    // Asynchronous operation (e.g., API call)
    setTimeout(() => {
      const user = { name: 'abhi', age: 130 };
      resolve(user);
    }, 2000);
  });
}

fetchUser()
  .then((user) => {
    console.log(user);
  })
  .catch((error) => {
    console.log(error);
  });
  • async/await: Async functions are defined using the async keyword, and await is used to pause the execution until a promise is resolved. It provides a more synchronous and readable code structure.
async function fetchUser() {
  return new Promise((resolve, reject) => {
    // Asynchronous operation (e.g., API call)
    setTimeout(() => {
      const user = { name: 'John', age: 30 };
      resolve(user);
    }, 2000);
  });
}

async function main() {
  try {
    const user = await fetchUser();
    console.log(user);
  } catch (error) {
    console.log(error);
  }
}

main();

2. Readability and Flow:

  • Promise: Promises use a chain of .then() and .catch() statements, which can sometimes lead to nested and complex code structures, known as "callback hell" or "promise chaining."
fetchUser()
  .then((user) => {
    return updateUser(user);
  })
  .then((updatedUser) => {
    return deleteUser(updatedUser.id);
  })
  .then(() => {
    console.log('User deleted successfully.');
  })
  .catch((error) => {
    console.log(error);
  });
  • async/await: Async/await provides a more linear and readable flow of code, similar to synchronous programming, making it easier to understand and maintain.
async function main() {
  try {
    const user = await fetchUser();
    const updatedUser = await updateUser(user);
    await deleteUser(updatedUser.id);
    console.log('User deleted successfully.');
  } catch (error) {
    console.log(error);
  }
}

main();

3. Error Handling:

  • Promise: Promises handle errors using the .catch() method, which can be attached at the end of the promise chain to catch any errors that occur during the asynchronous operations.
fetchUser()
  .then((user) => {
    console.log(user);
    throw new Error('Some error occurred.');
  })
  .catch((error) => {
    console.log(error);
  });
  • async/await: Async/await handles errors using traditional try-catch blocks, allowing for more straightforward and intuitive error handling.
async function main() {
  try {
    const user = await fetchUser();
    console.log(user);
    throw new Error('Some error occurred.');
  } catch (error) {
    console.log(error);
  }
}

main();

Scenario of choosing Promises and async await .

Promise and async await have his own strengths and suitable for different scenarios here we ‘ll discuses about few these scenarios that we should choose promise and async await

Use Promises when:

  1. You’re working with existing asynchronous code that already returns promises, such as browser APIs or third-party libraries.

  2. You need fine-grained control over the flow of asynchronous operations using methods like .then() and .catch().

  3. You want to handle multiple asynchronous operations concurrently using Promise.all() or Promise.race().

function fetchUser() {
  return new Promise((resolve, reject) => {
    // Asynchronous operation (e.g., API call)
    setTimeout(() => {
      const user = { name: 'John', age: 30 };
      resolve(user);
    }, 2000);
  });
}

fetchUser()
  .then((user) => {
    console.log(user);
  })
  .catch((error) => {
    console.log(error);
  });

Use async/await when:

  1. You want to write asynchronous code that appears more synchronous and readable, making it easier to understand and maintain.

  2. You need to pause the execution of code until a promise is resolved or rejected using the await keyword.

  3. You want to handle exceptions and errors using traditional try-catch blocks.

async function fetchUser() {
  return new Promise((resolve, reject) => {
    // Asynchronous operation (e.g., API call)
    setTimeout(() => {
      const user = { name: 'John', age: 30 };
      resolve(user);
    }, 2000);
  });
}

async function main() {
  try {
    const user = await fetchUser();
    console.log(user);
  } catch (error) {
    console.log(error);
  }
}

main();

Conclusion : in general, async/await provides a more concise and synchronous-like coding style, especially for handling sequential asynchronous operations. Promises are more suitable when working with existing promise-based APIs or when you need more control over the flow of asynchronous operations. It's worth noting that async/await is built on top of promises, so you can mix and match them as needed in your codebase.