# Demystifying Async/Await: A Comprehensive Guide

---

---

## Topics Covered

* What is async?
    
* What is await?
    
* How does async/await work behind the scenes?
    
* Example of using async/await
    
* Error Handling
    
* Interviews
    
* Async/Await vs Promise.then/.catch
    

---

### What is Async?

In JavaScript, `async` is a keyword used before a function to create an asynchronous function.

**Q: What is async?**

**A:** Async is a keyword used before a function to create an async function.

---

### Understanding Async Functions

An `async` function always returns a promise. There are two cases:

**Case 1:** If you explicitly return a promise.

```javascript
async function getData() {
  return Promise;
}
```

**Case 2:** If you don't return a promise, it wraps the value inside a promise.

```javascript
async function getData() {
  return "javascript";
}
```

This function always returns a promise.

Now, calling this function:

```javascript
async function getData() {
  return "javascript";
}

const dataPromise = getData();
console.log(dataPromise); // Output: Promise {'javascript'}
```

To retrieve the value from the promise, you use the `.then` method.

```javascript
dataPromise.then((res) => console.log(res));
```

Remember, it always returns a promise in any case; keep this in mind for interviews.

---

### Example of Returning a Promise

Let's create a promise and return it in an async function.

```javascript
const p = new Promise((resolve, reject) => {
  resolve("Promise Resolved values");
});

async function getData() {
  return p;
}

const dataPromise = getData();
dataPromise.then((res) => console.log(res));
```

---

### Handling Promises Before Async/Await

Before diving into async/await, let's understand how promises are handled without it.

```javascript
const p = new Promise((resolve, reject) => {
  resolve("Promise Resolved values");
});

function getData() {
  p.then((res) => console.log(res));
}

getData();
```

Now, let's handle the same promise using async/await.

```javascript
const p = new Promise((resolve, reject) => {
  resolve("Promise Resolved values");
});

async function handlePromise() {
  const val = await p;
  console.log(val);
}

handlePromise();
```

---

### Deep Dive into Async/Await

Consider a promise with a timeout:

```javascript
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise Resolved values");
  }, 10000);
});

async function handlePromise() {
  const val = await p;
  console.log(val);
}
handlePromise();
```

In normal handling, JavaScript doesn't wait for the promise to be resolved and moves on to the next line. However, with async/await, the engine waits for the promise to be resolved before moving to the next line.

---

### Understanding Async/Await in Detail

Now, let's explore the difference between normal handling and handling using async/await.

```javascript
async function handlePromise() {
  console.log("hello world "); // Printed quickly
  const val = await p; // Program waits for 10 seconds
  console.log("javascript ");
  console.log(val);

  // What happens now? Interview question
  // After 10 seconds, both promises will be printed
  const val2 = await p;
  console.log("javascript ");
  console.log(val2);
}
handlePromise();
```

So, the JavaScript engine is waiting for the promise to be resolved, and once resolved, it moves on to the next line.

---

### Handling Multiple Promises

Now, let's handle two promises:

```javascript
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise Resolved values");
  }, 10000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise Resolved values");
  }, 5000);
});

async function handlePromise() {
  console.log("hello world "); // Printed quickly
  const val = await p1; // Program waits for 10 seconds
  console.log("javascript ");
  console.log(val);

  const val2 = await p2;
  console.log("javascript ");
  console.log(val2);
}
handlePromise();
```

After 5 seconds, nothing will be printed, but after 10 seconds, both promises will be resolved and printed.

---

**Understanding Async/Await Execution Flow**

When this function is executed, it will go line by line as JavaScript is a synchronous, single-threaded language. Let's observe what happens under the call stack. Breakpoints have been set for clarity.

```javascript
// Call stack flow -> handlePromise() is pushed
// It will log `Hi` to the console
// Next, it encounters await where a promise is supposed to be resolved
// Will it wait for the promise to resolve and block the call stack? No
// Thus, handlePromise() execution gets suspended and moved out of the call stack
// When JavaScript encounters the await keyword, it suspends the function's execution until the promise is resolved
// So, `p` will get resolved after 5 seconds, and handlePromise() will be pushed to the call stack again after 5 seconds
// It will start executing from where it left off
// Now, it will log 'Hello There!' and 'Promise resolved value!!'
// Then, it will check whether `p2` is resolved or not
// It will find that since `p2` will take 10 seconds to resolve, the same process will repeat
// Execution will be suspended until the promise is resolved

// Thus, JS is not waiting, and the call stack is not getting blocked.

// Moreover, in the above scenario, what if p1 takes 10 seconds and p2 5 seconds?
// Even though p2 got resolved earlier, JS is a synchronous, single-threaded language
// It will first wait for p1 to be resolved and then will immediately execute all.
```

### Real-life Example - Fetch API

```javascript
async function handlePromise() {
  // fetch() => Response Object, which has a body as a Readable stream => Response.json() is also a promise, which when resolved => value
  const data = await fetch("https://api.github.com/users/jatin4224"); // Waited for this line to be resolved
  const res = await data.json(); // Waited for this data JSON to be resolved
  console.log(res);
}
handlePromise();
```

---

### Error Handling

Error handling in async/await is achieved using try-catch:

```javascript
async function handlePromise() {
  try {
    const data = await fetch("https://api.github.com/users/jatin4224");
    const res = await data.json();
    console.log(res);
  } catch (err) {
    console.log(err);
  }
}
handlePromise();
```

Another way to handle errors is using `.catch`:

```javascript
handlePromise().catch((err) => console.log(err));
```

Handling an invalid API URL:

```javascript
async function handlePromise() {
  try {
    const data = await fetch("https://invalid");
    const res = await data.json();
    console.log(res);
  } catch (err) {
    console.log(err);
  }
}
handlePromise();

handlePromise().catch((err) => console.log(err));
```

---

### Interview Tips

When asked about async/await, explain the concepts covered in this blog with examples. Be prepared to explain promises if required.

---

### Async/Await vs Promise.then/.catch

Async/await is essentially syntactic sugar around promises. It solves some of the shortcomings of promise chaining and enhances code readability. It is advisable to use async/await as it simplifies code structure and improves clarity.

---

---
