Intro
Before learning about async/await you should know what and how promises work in JavaScript. You can read about promises here
What is async/await?
async/await
were introduced in 2017, Before that managing asynchronous operations in javaScript was primarily done using promises.
While promises helped in the "callback hell" issue, they still introduced a certain level of complexity, especially when dealing with multiple async operations in sequence.
Async/await
was introduced to make working with asynchronous code even more easy and readable. It provides a syntax that looks and behaves like synchronous code.
It is still built on top of Promises and is compatible with all existing Promise-based APIs.
Creating an async function using async keyword 👇
async function functionName() {}
async function working
An async function created with async keyword will always return a promise.
There could be 2 situations:
- You return a promise explicitely like this
// explicitely returning the promise
async function functionName() {
return new Promise((resolve, reject) => {
resolve("Some data")
})
}
- You return any other value like number, object, string, array, etc, but here the JavaScript engine wraps that value inside a promise object to ensure that the value returned is a promise.
You will find second case in more professional code some examples such as fetch()
or promisified version of fs
methods or other promisified methods.
async function asyncFunction2() {
// this gets wrapped inside a promise object
return "String";
}
What about the await keyword?
The await
keyword is used inside an async
function to pause the function execution until a promise settles.
To understand this first understand how callstack and basic functions work 👇
JavaScript thread works by pushing the variables and function calls inside callstack
. This function is not popped out of the stack until the code inside the function is completed executing.
But when its an async
function with await
keyword used inside, the story is different.
When JavaScript thread sees the await
keyword inside the async function
, the function is suspended from the callstack
, meaning it is popped out until the promise is completed (resolved or rejected) and once promise is finished the function is again pushed on the stack and it continues from where it left off with the result of the promise.
This is where a lot of beginners get confused. So a point to note here is:
Point: Await keyword will only suspend the parent async function in which it is written. This means that JS thread is not blocked and can continue the other work out of the function.
Code example and Explanation
function returnData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Promise is resolved');
}, 3000);
});
}
async function fetchDataWithAwait() {
const data = await promisificaction("Promise");
console.log(data);
console.log("Thread waited because of await keyword!")
}
fetchDataWithAwait();
console.log("Thread is still free to work!");
Explanation of code:
JS thread sees the
returnData
function which returns a resolved value after 3 seconds (setTimeout function is making sure of 3 seconds delay)JS thread sees the
fetchDataWithAwait
function declaration.JS thread now sees the
fetchDataWithAwait()
call and pushes the function on the callstack.JS thread finds the
await
keyword and suspends this function from the callstack until promise is resolved (3 seconds)JS thread continues to next line and prints
"Thread is still free to work!"
on the consoleNow since the JS thread is idle, it pushes the
async function
back to the callstack and starts execution from where it left off."Promise is resolved"
is printed on the console."Thread waited because of await keyword!"
is now printed.
Output:
Why use aync/await when we already had promises?
Because the syntax of promises is confusing while await makes it more clear and readable.
Promises create a lot of confusion when you are dealing with API calls again and again in your code.
async/await
fixes that confusion.
Remember that async/await
still uses promises behind the scenes but it just makes the syntax more readable.
Using try/catch() to handle errors
Since async/await
does not handle errors by default so we wrap them inside a try and catch() block of code.
try() is used to try the piece of code we wrote and catch() catches any error thrown by the api calls like in this example. This ensures the proper error handling.
async function fetchDataWithAwait() {
try {
const data = await promisificaction("Promise");
console.log(data);
console.log("Thread waited because of await keyword!")
} catch (error) {
console.log(error);
}
}
fetchDataWithAwait();
Conclusion
Once you know how to use async/await
Async js becomes really easy. Took me many days to properly grasp all this but I tried to put this in easiest way possible.
After all it is said that if you can not explain something in easy terms then you don't know it properly. ;)
Top comments (0)