Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was reviewing a PR from a junior dev who was trying to build a user dashboard. He had written a chain of five different .then() blocks to fetch a user, then their preferences, then their recent orders, and finally the shipping status for each order. The code looked like a giant sideways pyramid, and he was struggling to pass a variable from the first .then() all the way down to the fifth one. He'd spent half his afternoon fighting with scope and "Promise { <pending> }" logs in the console. That's when I sat him down and showed him async/await. It didn't actually change how JavaScript handles the event loop, but it completely changed how he was able to reason about his code.

Writing Code That Reads Like a Story

At its core, async/await is syntactic sugar built on top of Promises. You aren't replacing Promises; you're just using a cleaner way to consume them. When you mark a function with the async keyword, you're telling JavaScript that this function will return a Promise, regardless of what you actually return inside it. But the real magic happens with await.

When you await a Promise, the execution of that specific function pauses until the Promise resolves. The rest of your application keeps running—the browser doesn't freeze—but inside that function, the code reads linearly. Look at the difference in this common scenario where we need to fetch a user and then their specific posts:

// The old "Promise Chain" way
function getUserData(userId) {
  return fetch(`/api/users/${userId}`)
    .then(res => res.json())
    .then(user => {
      return fetch(`/api/posts?userId=${user.id}`)
        .then(res => res.json())
        .then(posts => {
          return { user, posts };
        });
    });
}

// The async/await way
async function getUserData(userId) {
  const userRes = await fetch(`/api/users/${userId}`);
  const user = await userRes.json();
  
  const postsRes = await fetch(`/api/posts?userId=${user.id}`);
  const posts = await postsRes.json();
  
  return { user, posts };
}

Notice how in the second version, we don't have to nest our logic to keep the user object in scope for the second request. We just declare it and use it on the next line. It's much easier on the eyes and significantly easier to debug.

Managing Failures with Try and Catch

One thing that trips people up is error handling. With Promise chains, you just tack a .catch() onto the end. With async/await, we go back to a classic programming pattern: the try...catch block. I actually prefer this because it allows you to wrap multiple asynchronous calls—and any synchronous logic in between them—in a single error-handling net.

If any await call rejects, the execution jumps straight to the catch block. This prevents your app from crashing due to an "Unhandled Promise Rejection," which is a nightmare to track down in production. I usually recommend wrapping your await calls like this:

async function loadDashboard() {
  try {
    const data = await fetchCriticalData();
    renderUI(data);
  } catch (error) {
    console.error("Dashboard failed to load:", error);
    showErrorMessageToUser("Something went wrong. Please refresh.");
  }
}

Just a quick heads-up: don't over-use await. If you have two API calls that don't depend on each other, awaiting them one after the other creates a bottleneck. In those cases, you'll want to kick them both off and use Promise.all(), which we'll touch on in a later lesson. For now, focus on the clarity that async/await brings to your sequential logic.




📋 Practical Task

Exercise: Building a Sequential GitHub Profile Fetcher

Your task is to create a script that fetches a GitHub user's profile and then uses the url from their blog field to fetch the HTML of that blog page. This requires sequential asynchronous calls.

Requirements:

  • Create an async function called fetchUserAndBlog(username).
  • Use await` with the Fetch API to get user data from https://api.github.com/users/{username}.
  • Extract the blog URL from the resulting JSON.
  • Use await` again to fetch the content of that blog URL.
  • Wrap the entire process in a try...catch block to handle cases where the user doesn't exist or the blog URL is invalid.
  • Log the user's name and the first 100 characters of the blog's HTML to the console.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.