Everyone Can Learn Program
中文 Start learning
Core · FrontendLesson 7 of 8Free to read

Async and fetch · Frontend: HTML, CSS and JavaScript

How does a page load data without freezing?

Course contents

Why you need it

Loading a user's profile or a list of messages means asking a server and waiting, sometimes for seconds. If the page stopped while it waited, nothing could be clicked. JavaScript's answer is asynchronous code: start the request, carry on, and handle the answer when it arrives. Every modern app is built on it.

The intuition

Anything that takes time gives you a Promise: an IOU for a value that will arrive later.

const res = await fetch("https://api.example.com/user/1");
const user = await res.json();
  • **fetch(url)** sends an HTTP request and returns a Promise of the response.
  • **await pauses this function until the Promise settles, without freezing the page. You can only use it inside an async function**.
  • res.ok is true for status 200–299; res.status is the number. fetch does not throw on 404 or 500, so check res.ok.
  • res.json() is also a Promise: await it too.
  • Wrap it in **try { … } catch (err) { … }** to handle a network failure.

Order matters: ordinary code runs first, then Promise callbacks, then timers.

In this course fetch talks to a pretend API, so your code always gets the same answers.

Definition

Promise

An object standing for a value that isn't ready yet. It ends up fulfilled (with a value) or rejected (with an error).

async / await

async marks a function that can pause; await pauses it until a Promise settles and gives you the value.

fetch

The browser's function for HTTP requests. It resolves with a response for any status; check res.ok yourself.

Examples

Carry on while you wait

Run it in the lesson

setTimeout schedules work for later; the next line runs straight away.

console.log("1: start");
setTimeout(() => console.log("3: timer done"), 1000);
console.log("2: carrying on");
Output
1: start
2: carrying on
3: timer done
Step by step
  1. L2Schedules a function to run in 1 second, then moves on.
  2. L3Runs before the timer, even though it comes later in the code.

await the response, then await its JSON.

async function loadUser(id) {
  const res = await fetch(`https://api.example.com/user/${id}`);
  const user = await res.json();
  return user.name;
}

loadUser(1).then(name => console.log("Hello,", name));
console.log("waiting...");
Output
waiting...
Hello, Ada
Step by step
  1. L2The request goes out; this function pauses here.
  2. L3The body is JSON; res.json() parses it (and is async too).
  3. L7Calling an async function returns a Promise; .then runs when it's done.
  4. L8This prints first: nothing waited for loadUser.

When the server says no

Run it in the lesson

A 404 is still a response. Check res.ok.

async function loadUser(id) {
  const res = await fetch(`https://api.example.com/user/${id}`);
  if (!res.ok) {
    return `Error ${res.status}`;
  }
  const user = await res.json();
  return user.name;
}

async function main() {
  console.log(await loadUser(2));
  console.log(await loadUser(99));
}
main();
Output
Linus
Error 404
Step by step
  1. L3res.ok is false for 404, so we stop here with a message.
  2. L11await inside main waits for each result in turn.

Two requests at once

Run it in the lesson

Promise.all waits for several Promises in parallel.

async function nameOf(id) {
  const res = await fetch(`https://api.example.com/user/${id}`);
  const user = await res.json();
  return user.name;
}

async function main() {
  const names = await Promise.all([nameOf(1), nameOf(2)]);
  console.log(names);
}
main();
Output
[ 'Ada', 'Linus' ]
Step by step
  1. L8Both requests start at once; await waits until both have answered.

Common mistakes

Forgetting await

Without await you get the Promise, not the value: res.json is not a function, or Promise { <pending> } in the output.

Not checking res.ok

fetch only rejects when the network fails. A 404 or 500 arrives as a normal response, often with an error body that isn't the data you expect.

Waiting one by one

await a(); await b(); takes the time of both. If they don't depend on each other, await Promise.all([a(), b()]) takes only as long as the slower one.

Quick quiz

1. What does this print?

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
  1. A
    A
    D
    C
    B
  2. B
    A
    B
    C
    D
  3. C
    A
    D
    B
    C
Show the answer

Answer: A

Ordinary code first (A, D), then Promise callbacks (C), then timers (B), even a 0 ms timer.

2. The server answers 404 Not Found. What does `await fetch(url)` do?

  1. AGives a response with res.ok === false
  2. BThrows an error
  3. CReturns null
Show the answer

Answer: A

fetch only fails on network problems. HTTP errors are normal responses: check res.ok.

Practice

3 exercises in three steps: predict what a program prints, change a program to meet a new requirement, then write one from scratch. Your code runs in the browser and is checked the moment you submit.

  1. PredictOrder of events

    Type exactly what this prints, in order.

  2. ModifyMissing awaits

    getName(id) should return the user's name, but it crashes. Fix it.

  3. WriteLoad a profile

    Write async function loadProfile(id) that fetches https://api.example.com/user/<id> and returns:

    • "Ada (London)": the name and city, when the request succeeds
    • "User not found" when the response is not ok (like a 404)
    • "Network error" when fetch itself fails (use try/catch)

Practise this lesson

Open the interactive lesson to edit and run these examples and solve the exercises with instant feedback. Free to start, no sign-up.

Interactive lessons open in order. If you have not done the earlier ones yet, you start at the course map.

Terms in this lesson

TermChineseDefinition
PromisePromiseA value that will be ready later, or an error.
async / awaitasync / awaitWrite asynchronous code that reads top to bottom.
fetchfetchThe browser function for HTTP requests.