# Async/Await in JavaScript: Writing Cleaner Asynchronous Code

## Introduction

As developers, we have certainly heard the terms "synchronous" and "asynchronous" in JavaScript.  
  
By default, JavaScript is a synchronous, single-threaded programming language. This means that instructions can only run one after another, not in parallel.  
  
This isn't necessarily a bad thing, but problems arise when tasks take time to execute. You might wonder why that's an issue since there's no noticeable delay.

However, it's fine when there's only one task, but what happens when there are multiple requests or API calls? Then, the rest of the code has to wait until all those time consuming tasks are resolved.  
  
Now you might see the real problem. Fortunately, there are solutions that don't block the program and execution flow and might have heard about them.

*   Callbacks
    
*   Promises
    
*   Async/await
    

In this article we are going to talk about Async/Await and why they better than callbacks and promises.

* * *

## Why async/await was introduced?

You might be wondering why all three were introduced if they do the same thing. In programming, improvements happen step by step, and it's a similar story here.

### Callbacks:

The problem with callbacks was that after 4-5 nested callbacks, the code started to look messy and unreadable, a problem known as the **pyramid of doom** or **callback hell**.

```javascript
loginUser("kaneki", (user) => {
  getProfile(user.id, (profile) => {
    getPosts(profile.id, (posts) => {
      console.log(posts);
    });
  });
});
```

###   
Promises

Promises were better than callbacks because they didn't create callback hell, but after a certain point, promises also started to look complex to work with because of multiple level chaining.

```javascript
loginUser("kaneki")
  .then(user => getProfile(user.id))
  .then(profile => getPosts(profile.id))
  .then(posts => console.log(posts))
  .catch(err => console.error(err));
```

  
The thing is, chaining promises together just like callbacks can get pretty bulky and confusing. That's why Async and Await was brought about.

* * *

## How async functions work

In this we define async function and write code inside that, remember async function always returns a promise.

```javascript
const asyncFunc = async() => {
    // code here
};

const test = asyncFunc();
console.log(test);
```

The code inside an async function is blocking, but it doesn't stop program execution because things happen in parallel.

```javascript
const asyncFunc = async () => {
    const response = await fetch(resource);
       const data = await response.json();
}

console.log(1);
console.log(2);

asyncFunc().then(data => console.log(data));

console.log(3);
console.log(4);

// 1
// 2
// 3
// 4
// data returned by asyncFunc
```

For time consuming operations, we use `await`.

### `await` keyword concept

`await` pauses the execution of the **async function** until the Promise resolves or rejects. It waits for the result (e.g., from `fetch`) and then assigns it to the variable once the Promise is fulfilled.

This is how `async/await` works.

Meanwhile, the event loop continues executing other tasks, so the main thread is not blocked. Only the async function is paused, not the entire program.

Once the Promise resolves, execution resumes from the same point and the remaining code in that function runs.

* * *

## Error handling with async code

For error handling in async functions, `try...catch` is generally preferred because it keeps the code clean and readable.

Code that has a possibility of failure is placed inside the `try` block. If an error occurs, it is caught in the `catch` block, where it can be handled properly for better control and stability.

```javascript
async function getData() {
  try {
    console.log("Dattebayo");
  } catch (err) {
    console.error("Error:", err.message);
  }
}
```

JavaScript also allows creating **custom errors** using the `Error` class. This helps in handling different types of errors more efficiently and makes debugging easier by providing meaningful error messages.

* * *

## Promises vs Async/Await

Before `async/await` was introduced, **Promises** were the primary way to handle asynchronous (non-blocking) operations in JavaScript.

With the introduction of `async/await`, code became more readable and easier to manage. However, this doesn’t replace Promises `async/await` is simply a cleaner syntax built on top of them.

Promises are still essential, especially for handling multiple asynchronous operations. They provide powerful built-in methods such as:

*   `Promise.all()` -> runs multiple promises in parallel and fails fast
    
*   `Promise.allSettled()` -> waits for all promises, regardless of outcome
    
*   `Promise.any()` -> returns the first successfully resolved promise
    

These methods make Promises highly effective for managing concurrency and complex async workflows.

Let's compare promises and async/await side by side:

| Comparison Factor | Promises | Async/Await |
| --- | --- | --- |
| Syntax | `.then().catch()` chaining | `try...catch` with `await` |
| Readability | Less readable (complex chains) | More readable (sync-like) |
| Code Flow | Chaining-based | Linear, step-by-step |
| Error Handling | `.catch()` | `try...catch` |
| Debugging | Harder in long chains | Easier |
| Abstraction Level | Low-level (direct API) | High-level (syntactic sugar) |
| Use Case | Simple pipelines | Complex logic |
| Nesting | Can become nested | Avoids nesting |
| Parallel Execution | `Promise.all()` | `Promise.all()` |
| Execution Control | No pause, uses chaining | Pauses async function |

* * *

## Conclusion

In programming, things evolve gradually. Over time, better approaches emerge. For handling asynchronous code, the evolution moved from **callbacks → Promises → async/await**.

Each step improved readability, maintainability, and control. However, it’s important to understand the **foundations**, not just the latest abstraction.

By learning how these concepts evolved, we develop stronger problem solving skills and a deeper understanding of how systems work.

That’s how growth happens in programming and in real life.

Hope you like this blog❤️
