In this article, you will learn about Async/Await in javaScript, what it really is, and how it works behind the scenes. What is Async/Await?
Async/Await is nothing but a syntactical sugar to work with promises in a more comfortable fashion. It’s surprisingly easy to understand and use than Promises.
Async/Await attempts to solve one of the biggest pains in the language since its beginning that is synchrony.
They allow you to write promise-based code as if it were synchronous, but without blocking the main thread. They make your asynchronous code less mouthful and more readable.
Before I start with Async/Await, I would suggest you take a look at my article on Promises in JavaScript to understand the Promises first. Because you need to understand Promises before you can understand how to use Async/Await.
ASYNC/AWAIT WORKING & 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
}
}
If you use the async
keyword in a function definition, then only you can use await
within the function.
When you await
a promise, the function is paused in a non-blocking way until the promise returns any value.
If the promise resolves
, you get the resolved
value back. If the promise rejects
, the rejected
value is thrown which is nothing but an error.
EXAMPLE TO UNDERSTAND THE ASYNC/AWAIT:
What are we doing?
Here, we are creating a
product
and as soon as we create aproduct
we want to fetch all theproducts
that are stored in the database, including newly createdproduct
.In case any
error
occurs we want toreject
the promise, catch that rejection in thetry and catch
block, and instead of crashing our app, we want to simply console log the error without fetching the products.
// Let's assume that this `products` variable is a data that is
// already present in our database
const products = [
{
title: "Mobile",
price: "13999",
},
{
title: "Laptop",
price: "40999",
},
{
title: "Headphones",
price: "3999",
},
];
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);
};
// asynv 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 reject
ing the promise.
When you run the above code you will get the following output:
If we receive the product, that means error = false
:
When we pass the product in
createProduct()
, the error
becomes false
. It will return the resolved
value (after 3 seconds). We will store that resolved
value in the productMsg
variable and after that, we will console log that value/message, and also, we will fetch all the products by calling the fetchProducts()
function.
If we don't receive the product, that means error = true
:
When we don't pass the product
in createProduct()
, the error
becomes true
. It will return the rejected
value (after 3 seconds). We will catch that rejected
value in the catch () {}
block and we will console log that error message. This is how the error handling happens in async/await.
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 async/await function all the callbacks are gone. This makes it easier to read, especially for those who are not that familiar with promises.
DO THINGS IN PARALLEL:
Even though you're writing code that looks synchronous, ensure you don't miss the opportunity to do things in parallel.
The following code will take 15 seconds to complete: (Not recommended)
const asyncFunc = async() => {
await promise1(5000); // promise1 will take 5 seconds to complete
await promise2(5000); // promise2 will take 5 seconds to complete
await promise3(5000); // promise3 will take 5 seconds to complete
// after 15 seconds it will return "done!"
return "done!";
}
Now, take a look at the following code: (Recommended)
const asyncFunc = async() => {
// following promises will start a 5 seconds timer asynchronously/parallelly
const prom1 = promise1(5000);
const prom2 = promise2(5000);
const prom3 = promise3(5000);
// when you declare promises using the above method
// all the promises will run parallelly
await prom1;
await prom2;
await prom3;
// after 5 seconds it will return "done!", which is much much faster.
return "done!";
}
Async/Await makes execution sequential. It's not necessarily a bad thing, but having paralleled execution is much faster.
CONCLUSION:
Before Async/Await functions, JavaScript code that relied on lots of asynchronous events (using callbacks) would end up in what some called “callback hell” which is a chain of functions and callbacks that was very difficult to read and understand.
Async/Await allows us to write asynchronous JavaScript code that reads much more clear, efficient, and easy to understand. Also, it makes sure that the function will always return 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.
I hope you have learned something new! If you found this article useful, be sure to share, follow and support!
Thank you for reading!
Also, Make sure to subscribe our newsletter on blog.learncodeonline.in and never miss any upcoming articles related to programming just like this one.
I hope this post will help you in your journey. Keep learning!