[JavaScript Series 5] Fetching Data with async/await and fetch

한국어 버전

Now that you know how to manipulate the DOM, let’s connect the page to real server data. fetch is the browser-native network helper, and async/await makes Promise flows readable line by line.

Key terms

  1. async/await: keywords that let you read Promises sequentially. Execution pauses on an await line until that Promise settles.
  2. AbortController: a tool that cancels network requests when they take too long.

Core ideas

  • Promise: a box that says “I will deliver the result later.” It starts pending and settles into fulfilled or rejected.
  • async/await: a syntax that makes Promise chains read like natural steps. await pauses the function until the Promise resolves or rejects.
  • fetch: the HTTP API inside browsers. Because a connection that reaches the network counts as “successful,” you must still inspect response.ok.
  • Loading/error state: UI that tells the user what is happening. Combine skeletons, spinners, or text to reflect progress.
  • AbortController: the mechanism for canceling slow requests. Pass the signal to fetch, then trigger a timeout or cancel button when needed.

Code examples

async function loadPost(id) {
  const response = await fetch(`/api/posts/${id}`);
  if (!response.ok) {
    throw new Error("Failed to load the post");
  }
  return response.json();
}

loadPost(1)
  .then((post) => console.log(post.title))
  .catch((error) => console.error(error.message));

response.ok reports whether the HTTP status is 200–299. The network might be fine while the server returns 404, so you must check it.

const status = document.querySelector(".status");
const list = document.querySelector(".post-list");

async function loadPosts() {
  try {
    if (status) status.textContent = "Loading";
    const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
    if (!response.ok) throw new Error("Network error");
    const posts = await response.json();

    if (list) {
      list.innerHTML = posts
        .map((post) => `<li class="post-item">${post.title}</li>`)
        .join("");
    }
    if (status) status.textContent = "Done";
  } catch (error) {
    if (status) {
      status.textContent = error instanceof Error ? error.message : "Unknown error";
    }
  }
}

loadPosts();

Even simple status text reassures the user. Later you can add skeletons or modals.

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 4000);

try {
  const response = await fetch("/api/attendance", { signal: controller.signal });
  clearTimeout(timeout);
  const data = await response.json();
  renderAttendance(data);
} catch (error) {
  if (error.name === "AbortError") {
    showToast("The network is slow. Please try again.");
  }
}

When the network crawls—think dorm Wi‑Fi—canceling the request and asking the user to retry prevents the UI from looking frozen.

async function loadDashboard() {
  const [profile, todos] = await Promise.all([
    fetch("/api/profile").then((res) => res.json()),
    fetch("/api/todos").then((res) => res.json()),
  ]);
  return { profile, todos };
}

Promise.all is for independent requests. Once all of them resolve you receive the results in order.

Why it matters

  • External data powers pages such as event registration portals, so loading and error states directly influence user trust.
  • When you can explain the async/await structure, code reviews and demos become clearer: “we wait here, then update the screen there.”
  • On unstable networks, AbortController prevents the app from appearing hung.

Practice

  • Follow along: call the JSONPlaceholder posts endpoint and update loading, success, and error text in that order.
  • Extend: fetch /posts and /users simultaneously with Promise.all and render cards with author names.
  • Debug: use an incorrect URL to trigger HTTP 404, compare behavior with and without the response.ok guard, and note the difference.
  • Done when: you can reproduce the flow of loading message → data render → error message or retry button without console warnings.

Wrap-up

With fetch plus async/await you can wire the frontend to the backend directly. Next we will organize the fetched data and split it into modules.

💬 댓글

이 글에 대한 의견을 남겨주세요