# Async HTTP

Network requests take time. Browser JavaScript starts the request and continues running; a callback or Promise continuation runs when the result is ready.

# From callbacks to async/await

XMLHttpRequest exposes an older callback-oriented API. A minimal example:

const request = new XMLHttpRequest();
request.addEventListener('load', () => {
  const data = JSON.parse(request.responseText);
  console.log(data);
});
request.open('GET', 'data.json');
request.send();

fetch returns a Promise. Promises can be chained with .then()/.catch() or written with async/await:

async function loadData() {
  const response = await fetch('data.json');
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }

  return response.json();
}

loadData()
  .then(data => console.log(data))
  .catch(error => console.error('Loading failed', error));

fetch rejects for network failures, but it does not reject automatically for HTTP 4xx or 5xx responses. Check response.ok or response.status yourself.

# Request and UI states

A useful UI distinguishes at least three states:

  1. Loading — the request is in progress.
  2. Success — the response was valid and data was rendered.
  3. Failure — the network, HTTP status, or JSON parsing failed.

Requests can also specify a method, headers, and body:

await fetch('/messages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ text: 'Hello' })
});

The browser’s same-origin policy and CORS headers can limit which responses a script may read. See Lecture 1’s browser concerns.

# Exercise

Create a small data.json file, serve it over HTTP, and run the fetch example above against it: show a loading message, render the parsed data, and display a useful error when the request or parsing fails.