Async/Await in JavaScript with Easiest Explanation!

Async/Await in JavaScript with Easiest Explanation!

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:

  1. You return a promise explicitely with return new Promise((resolve, reject) => {})

  2. 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:

  1. JS thread sees the returnData function which returns a resolved value after 3 seconds (setTimeout function is making sure of 3 seconds delay)

  2. JS thread sees the fetchDataWithAwait function declaration.

  3. JS thread now sees the fetchDataWithAwait() call and pushes the function on the callstack.

  4. JS thread finds the await keyword and suspends this function from the callstack until promise is resolved (3 seconds)

  5. JS thread continues to next line and prints "Thread is still free to work!" on the console

  6. Now since the JS thread is idle, it pushes the async function back to the callstack and starts execution from where it left off.

  7. "Promise is resolved" is printed on the console.

  8. "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. ;)

Did you find this article valuable?

Support Shubh Sharma by becoming a sponsor. Any amount is appreciated!