Async/Await in JavaScript

• Yash Gupta • Feb 19, 2025 • 8 mins read

Async/Await is simply syntactic sugar that makes working with promises more convenient and readable. It provides a simpler and more intuitive way to handle asynchronous operations compared to traditional Promises.

Async/Await attempts to solve one of the biggest pains in the language since its beginning that is synchrony.

They let you write promise-based code in a synchronous style without blocking the main thread, making your asynchronous code cleaner and more readable.

Before I start with Async/Await, I suggest you look at my article on Promises in JavaScript to understand them. You need to understand Promises before you can understand how to use Async/Await.

Async/Await Working and Syntax:

const asyncFunc = async () => {
// to handle errors in async/await we use try and catch block
try {
// we will store only resolved value in resolvedValue variable
const resolvedValue = await promise;
}
catch (rejectedValue) {
// handle only rejected value (error) here
}
}

You can use await inside a function only if it is defined with the async keyword.

When you await a promise, the function is paused in a non-blocking way until the promise returns any value.

If the promise resolves, it returns the resolved value. If it rejects, the rejected value is thrown as an error.

Example to Understand the Async/Await:

What are we doing?

  • Here, we are creating a product. As soon as we create a product, we want to fetch all the products stored in the database, including the newly created product.
  • If an error occurs, we should reject the promise, catch the rejection in a try-catch block, and log the error to the console instead of crashing the app or fetching the products.

// Let's assume that this `products` variable is a data that is
// already present in our database
const products = [
{
title: "Speaker",
price: "7999",
},
{
title: "Laptop",
price: "75999",
},
{
title: "Headphones",
price: "5999",
},
];

const createProduct = (product) => {
return new Promise((resolve, reject) => {
// here setTimeout is immitating time require to fetch data/api from server
setTimeout(() => {
// lets say there is no error
let error;
if (product) {
// if we receive a product that means there is no error
error = false;
// so we will push the received product in our existing products' array
products.push(product);
} else {
// if we don't receive a product that means there is some error
error = true;
}
if (!error) {
resolve("Created the product successfully");
} else {
reject("Some error occurred");
}
}, 3000);
});
};

let fetchProducts = () => {
console.log("fetching the products...\n");
// here setTimeout is immitating time require to fetch data/api from server
setTimeout(() => {
products.forEach((prod) => {
console.log(prod.title);
});
}, 2000);
};

// async function
const asynFunc = async () => {
// try and catch for error handeling
try {
// we will store the 'resolved' value in productsMsg
let productsMsg = await createProduct({
title: "new product",
price: "399",
});
console.log(productsMsg);
fetchProducts();
} catch (error) {
// we will get 'rejected' value as an error
console.log(error);
}
};

asynFunc();

console.log("next lines of code\n");

When we call asyncFunc() which is an async function, it will wait until createProduct() promise returns a resolved or rejected value (Depending on the value of the error variable).

If the promise is resolved then only it will fetch the products by executing fetchProducts(), otherwise, it will throw an error by rejecting the promise

Real World Use Case using axios() :

Say we wanted to fetch a URL and console log the response. Here's how it looks using Promises:

const fetchUrl = (url) => {
return axios
.get(url)
.then((response) => {
console.log(response.data);
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
};

And here's the same thing using async/await functions:

const fetchUrl = async (url) => {
try {
const response = await axios.get(url);
console.log(response.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};

If you notice, unlike promises in the async/await function, all the callbacks are gone. This makes it easier to read, especially for those who are not familiar with promises.

Conclusion:

  • Before Async/Await functions, JavaScript code that relied on many asynchronous events (using callbacks) would end up in what some called “callback hell,” a chain of functions and callbacks that was very difficult to read and understand.
  • Async/Await enables us to write asynchronous JavaScript code that is clearer, more efficient, and easier to understand. It also ensures that the function always returns a promise.
  • With Async/Await we rarely need to write promise.then().catch(), but we still shouldn’t forget that they are based on promises.
Thank you for reading!

I hope this post will help you in your journey. Keep learning!

Yash Gupta
I am passionate about tech and coding. I share expert insights on Test Automation (Selenium, Cypress, Playwright), API Automation, JavaScript, Python, Svelte, Vue.js, ReactJS, Angular, Flutter, and more. Stay updated with the latest trends! 🚀