JavaScript10 min read

JavaScript async/await: Modern Async Code

Master async/await syntax. Write cleaner asynchronous code with async functions and await keyword.

Alex Thompson
December 19, 2025
0.0k0

JavaScript async/await

The Problem with Promise Chains

Promises work, but they can get messy:

```javascript fetch('/api/user') .then(response => response.json()) .then(user => { return fetch(`/api/posts/${user.id}`); }) .then(response => response.json()) .then(posts => { return fetch(`/api/comments/${posts[0].id}`); }) .then(response => response.json()) .then(comments => { console.log(comments); }) .catch(error => { console.error(error); }); ```

**Problems:** - Hard to read - Lots of nesting - Error handling is at the end - Feels backwards

The Solution: async/await

async/await makes async code look like regular code:

```javascript async function loadData() { const userResponse = await fetch('/api/user'); const user = await userResponse.json(); const postsResponse = await fetch(`/api/posts/${user.id}`); const posts = await postsResponse.json(); const commentsResponse = await fetch(`/api/comments/${posts[0].id}`); const comments = await commentsResponse.json(); console.log(comments); } ```

**Much easier to read!** It reads top to bottom, like regular code.

How async/await Works

Think of `await` like waiting in line:

``` ┌─────────────────────┐ │ async function │ │ │ │ Step 1: await │ ← Wait here for result │ fetch('/api/user') │ │ │ │ │ ▼ │ │ Step 2: await │ ← Then continue │ response.json() │ │ │ │ │ ▼ │ │ Step 3: await │ ← Wait again │ fetch('/api/posts')│ │ │ │ │ ▼ │ │ Step 4: Use data │ ← Finally use it └─────────────────────┘ ```

**Key point:** `await` pauses the function until the Promise finishes. Then it continues to the next line.

Step-by-Step: Creating an async Function

**Step 1:** Add `async` keyword ```javascript async function loadData() { } ```

**Step 2:** Use `await` with Promises ```javascript async function loadData() { const response = await fetch('/api/data'); } ```

**Step 3:** Continue with the result ```javascript async function loadData() { const response = await fetch('/api/data'); const data = await response.json(); console.log(data); } ```

**What happens:** 1. Function starts 2. Waits for fetch to finish 3. Gets the response 4. Waits for json() to finish 5. Gets the data 6. Logs it

Error Handling with try/catch

With async/await, you use try/catch like regular code:

```javascript async function loadData() { try { const response = await fetch('/api/data'); const data = await response.json(); return data; } catch (error) { console.error('Something went wrong:', error); return null; } } ```

**Flow:** ``` ┌─────────────┐ │ try { │ │ await │ ← If this fails... │ } │ └──────┬──────┘ │ ┌──────▼──────┐ │ catch { │ ← ...jump here │ handle │ │ } │ └─────────────┘ ```

Real Example: Loading User Profile

```javascript async function loadUserProfile(userId) { try { // Step 1: Get user const userResponse = await fetch(`/api/users/${userId}`); if (!userResponse.ok) { throw new Error('User not found'); } const user = await userResponse.json(); // Step 2: Get user's posts const postsResponse = await fetch(`/api/users/${userId}/posts`); const posts = await postsResponse.json(); // Step 3: Get user's followers const followersResponse = await fetch(`/api/users/${userId}/followers`); const followers = await followersResponse.json(); // Step 4: Return everything return { user, posts, followers }; } catch (error) { console.error('Failed to load profile:', error); throw error; } }

// Use it loadUserProfile(123) .then(profile => { console.log('Profile loaded:', profile); }); ```

**Notice:** It reads like a story. Step 1, then Step 2, then Step 3. Much clearer than promise chains.

Using async/await with Loops

You can use await in loops:

```javascript async function loadMultipleUsers(userIds) { const users = []; for (const id of userIds) { const response = await fetch(`/api/users/${id}`); const user = await response.json(); users.push(user); } return users; } ```

**Important:** This does them one at a time. If you want them all at once, use Promise.all:

```javascript async function loadMultipleUsers(userIds) { const promises = userIds.map(id => fetch(`/api/users/${id}`).then(r => r.json()) ); const users = await Promise.all(promises); return users; } ```

Common Mistakes

**Mistake 1: Forgetting await** ```javascript async function loadData() { const response = fetch('/api/data'); // Missing await! const data = response.json(); // This will fail! } ```

**Mistake 2: Not handling errors** ```javascript async function loadData() { const response = await fetch('/api/data'); // What if this fails? const data = await response.json(); } ```

Always use try/catch!

Quick Tips

1. **Use async/await for new code** - It's the modern standard 2. **Always use try/catch** - Promises can reject 3. **await only works in async functions** - You can't use it in regular functions 4. **Use Promise.all for parallel operations** - Don't await in a loop if you don't need to

async/await makes async code much easier to read and write. It's what most developers use today. Once you're comfortable with it, you'll rarely go back to promise chains.

#JavaScript#async/await#Promises#Async#Intermediate