Skip to main content

Async/Await vs. Promises ( They're Both Awesome )

· 6 min read
Deepak Thapliyal

Javascript is an asynchronous programming language. the main reason why its asynchronous because it is also single threaded.

info

you can use Webworkers to utilise more then one threads at a time.

What is asynchronous Programming:

In programming, the term asynchronous refers to code that doesn't block the main program flow while waiting for long-running operations to complete. This is in contrast to synchronous code, which executes line by line and waits for each operation to finish before moving on.

Why do we need it:

Suppose we're making an api call to the server which takes 5 second of time, now instead of waiting for 5 seconds we can do some other computations like showing

In programming languages like javascript which is single treaded it means it can only utilise one thread at ones, so you would have to wait for code to execute line by line, which can increase wait time since we can only run one process at a time.

That's why javascript is Asynchronous

Let's understand promises and how to implement them in javascript, we will talk about how we use promises and async/await to do our asynchronous operations.

Promises

Has someone ever made a promise to you?

Promises in JavaScript are similar to that. When a promise is made, it represents a value that may be available now, in the future, or never.

A promise in JavaScript can be in one of three states:

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

Here's an example of a promise:

let promise = new Promise((resolve, reject) => {
// Simulate an asynchronous operation using setTimeout
setTimeout(() => {
let result = true; // Simulating result positive value
if (result) {
resolve("Promise fulfilled!");
} else {
reject("Promise rejected!");
}
}, 1000);
});

promise
.then((message) => {
console.log(message); // Logs "Promise fulfilled!" if the promise is resolved
})
.catch((error) => {
console.log(error); // Logs "Promise rejected!" if the promise is rejected
});

Here is a simple breakdown of above code:

1. Creating a Promise:

  • let promise = new Promise((resolve, reject) => {...});
    • This line creates a new Promise object named promise.
    • The Promise constructor takes an executor function with two arguments: resolve and reject.

2. Simulating Asynchronous Operation:

  • setTimeout(() => {...}, 1000);
    • Inside the executor function, a setTimeout function is used to simulate an asynchronous operation (suppose we are making an api call and it is taking 1 second)
    • This function delays the execution of the code inside it for 1 second (1000 milliseconds).
    • The anonymous function passed to setTimeout will be executed after the delay.

3. Resolving or Rejecting the Promise:

  • let result = true; // Let's assume our api returned positive response like 201
    • A variable result is declared and assigned a value (here, true). This simulates the outcome of the asynchronous operation.
  • if (result) { resolve("Promise fulfilled!"); } else { reject("Promise rejected!"); }
    • An if-else statement checks the value of result.
      • If result is truthy (here, true), the resolve function is called with the message "Promise fulfilled!". This indicates successful completion of the asynchronous operation.
      • If result is falsy, the reject function is called with the message "Promise rejected!". This indicates an error occurred during the operation.

4. Handling Promise Resolution/Rejection:

  • promise.then((message) => {...}, .catch((error) => {...});
    • After creating the promise, the .then and .catch methods are chained to handle its outcome.
    • .then takes a callback function that executes if the promise is resolved. Here, it logs the message received through resolve ("Promise fulfilled!").
    • .catch takes a callback function that executes if the promise is rejected. Here, it logs the error message received through reject ("Promise rejected!").

This is how you do Promises in javascript now let's talk about Async/await

Async await

In javascript async await is just a better way of doing promises, it gives us better syntax and its easier to understand

Let's see the example of promises

const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: 'John Doe', age: 30 };
resolve(data); // Simulating successful data fetching
}, 2000);
});
};

const displayData = async () => {
try {
console.log('Fetching data...');
const data = await fetchData(); // Wait for the promise to resolve
console.log('Data:', data);
} catch (error) {
console.error('Error:', error);
}
};

displayData();

Let's break down the above code

1. Asynchronous Function (displayData):

  • const displayData = async () => { ... }
    • The async keyword before the function declaration marks displayData as an asynchronous function.
    • Asynchronous functions implicitly return a promise.

2. Error Handling (try...catch):

  • try { ... } catch (error) { ... }
    • A try...catch block is used to handle potential errors during the asynchronous operation.
      • Code within the try block is executed. If an error occurs, it's caught by the catch block.

3. await Keyword:

  • const data = await fetchData();
    • The await keyword is used inside the try block.
    • It pauses the execution of displayData until the promise returned by fetchData() is either resolved or rejected.

4. Promise Resolution:

  • When fetchData()'s promise resolves (after 2 seconds), the value it resolves with (the data object) is assigned to the data variable.
  • Execution continues to the next line (console.log('Data:', data);), logging the fetched data.

5. Promise Rejection (If Any):

  • If fetchData()'s promise were to be rejected (e.g., due to a network error), the catch block would be executed.
  • The error object would contain information about the rejection, which is then logged to the console.

In essence, async/await provides a more synchronous-looking way to handle asynchronous operations in JavaScript, making code easier to read and reason about.

Conclusion:

Both Promises and Async/Await are powerful tools for dealing with asynchronous operations in JavaScript. Promises provide a structured way to handle the eventual success or failure of these operations. Async/Await builds upon Promises, offering a more readable and intuitive syntax that resembles synchronous code.

Choose Promises when:

  • You need a more fundamental way of working with asynchronous code.
  • You're dealing with older browsers that might not fully support Async/Await.

Choose Async/Await when:

  • You want a cleaner and more synchronous-like coding style.
  • Error handling and sequential asynchronous operations are a priority.

At the end it all depends on your project's needs and your preference as a developer.