# 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:
- Loading — the request is in progress.
- Success — the response was valid and data was rendered.
- 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.