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 keyword?
async/await
were introduced in 2017, Before that time 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.
Asyn/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.
async function functionName() {}
async function working
An async function created with async
keyword will always return a promise.
There could be 2 cases:
You return a promise explicitely with
return new Promise((resolve, reject) => {})
You return any other value but the JS 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.
Example:
// explicitely returning promise
async function asyncFunction1() {
return new Promise((resolve, reject) => {
// async operation
resolve(data);
});
}
async function asyncFunction2() {
// this gets wrapped inside a promise object
return "String";
}
What is await keyword?
The await keyword is used inside an async function to pause the function execution until a promise settles.
JS 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 inside the story is different.
When JS 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/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 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
Example to explain:
function returnData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Promise is resolved');
}, 3000);
});
}
async function fetchDataWithAwait() {
const data = await returnData();
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 aresolved
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 bad and confusing while await makes it more clear.
Promises created a lot of confusion when you are doing API calls again and again in your code. async/await fixes that confusion. Remember that async/await
still uses promises 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. ;)