# Async/Await in JavaScript: Writing Cleaner Asynchronous Code

## Introduction

As JavaScript applications grew more complex, handling asynchronous operations like API calls, file reading, or timers became messy and hard to maintain. Developers initially relied on **callbacks**, then moved to **Promises**, but both approaches had readability issues.

That’s where **async/await** comes in a cleaner, more readable way to handle asynchronous code.

## Why Async/Await Was Introduced

Before async/await:

*   **Callbacks** led to *callback hell* (nested functions)
    
*   **Promises** improved things but still required chaining with `.then()` and `.catch()`
    

### Problem Example (Promises)

```javascript
fetchData()
  .then(data => processData(data))
  .then(result => saveData(result))
  .catch(err => handleError(err));
```

This is better than callbacks, but still not very readable when logic grows.

### Solution: Async/Await

Async/await was introduced to:

*   Make asynchronous code look like synchronous code
    
*   Improve readability and maintainability
    
*   Simplify error handling
    

## How Async Functions Work

An **async function** always returns a **Promise**.

### Syntax:

```javascript
async function myFunction() {
  return "Hello";
}
```

Even though it returns a string, JavaScript wraps it in a Promise:

```javascript
myFunction().then(console.log); // Hello
```

## Await Keyword Concept

The `await` keyword pauses execution until a Promise is resolved.

### Example:

```javascript
async function getData() {
  let response = await fetch("https://api.example.com/data");
  let data = await response.json();
  console.log(data);
}
```

### Key Points:

*   `await` can only be used inside `async` functions
    
*   It makes asynchronous code behave like synchronous code
    
*   It improves clarity
    

![](https://cdn.hashnode.com/uploads/covers/69501e8b80eb08d5055e2d2e/b4d16608-62ad-483e-9d5b-f32b0d8ee6f7.jpg align="center")

## Real-Life Example

Imagine ordering food:

### Without async/await (Promises)

```javascript
orderFood()
  .then(food => eatFood(food))
  .then(() => payBill())
  .catch(err => console.log(err));
```

### With async/await

```javascript
async function dine() {
  try {
    const food = await orderFood();
    await eatFood(food);
    await payBill();
  } catch (err) {
    console.log(err);
  }
}
```

Feels more like a step-by-step process, right?

![](https://cdn.hashnode.com/uploads/covers/69501e8b80eb08d5055e2d2e/0a0806e9-3d11-4766-a0f1-4f4784d66478.jpg align="center")

## Error Handling with Async Code

With Promises:

```javascript
fetchData()
  .then(data => console.log(data))
  .catch(err => console.log(err));
```

With async/await:

```javascript
async function fetchDataHandler() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}
```

### Why it's better:

*   Uses familiar `try...catch`
    
*   Easier to debug
    
*   Cleaner structure
    

## Comparison: Promises vs Async/Await

| Feature | Promises | Async/Await |
| --- | --- | --- |
| Syntax | `.then().catch()` | `async/await` |
| Readability | Medium | High |
| Error Handling | `.catch()` | `try...catch` |
| Code Structure | Chain-based | Linear (top-to-bottom) |

## Async/Await = Syntactic Sugar

Async/await is not replacing Promises it’s built **on top of them**.

It’s just a cleaner way to write Promise-based code.

Example:

```javascript
async function example() {
  return "Hello";
}
```

Is equivalent to:

```javascript
function example() {
  return Promise.resolve("Hello");
}
```

Cleaner and more readable code

*   Easier debugging
    
*   Better error handling
    
*   Looks synchronous but works asynchronously
    

## When Not to Overuse It

*   When running multiple independent async tasks (use Promise. All)
    
*   When performance matters (sequential `await` can slow things)
    

## Summery

As JavaScript applications became more complex, managing asynchronous operations using callbacks led to issues like "callback hell," making the code difficult to maintain. Although Promises improved the situation by providing a more structured way to handle asynchronous tasks, they still required chaining methods like `.then()` and `.catch()`, which could become cumbersome. To address these issues, async/await was introduced as a cleaner, more readable way to handle asynchronous code, making it look and behave more like synchronous code.

Async/await simplifies the process by allowing developers to write asynchronous code in a linear, top-to-bottom fashion. An async function always returns a Promise, and the `await` keyword pauses the function execution until a Promise is resolved. This approach not only enhances code readability and maintainability but also simplifies error handling through the familiar `try...catch` syntax. For example, instead of chaining multiple `.then()` calls, developers can write code that resembles a step-by-step procedure, improving clarity and making debugging easier.

While async/await provides a cleaner syntax for writing asynchronous code, it's important to note that it is built on top of Promises and does not replace them. It offers a syntactic sugar that enhances readability and error handling but should be used judiciously. For tasks that can run concurrently or where performance is critical, using `Promise.all` might be more appropriate. Overall, async/await makes it easier to write, read, and maintain asynchronous JavaScript code.
