Asynchronous JavaScript and the Fetch APILesson 4.5
Handling API errors and loading states in the UI
loading state pattern, error state, AbortController, fetch timeout, retry logic, user feedback, finally block
API Error and Loading State Handling
Every fetch operation has three possible UI states: loading, success, and error. Your UI should reflect all three.
async function loadPosts() {
const status = document.querySelector('#status');
const list = document.querySelector('#post-list');
status.textContent = 'Loading...';
list.innerHTML = '';
try {
const res = await fetch('/api/posts');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const posts = await res.json();
renderPosts(posts);
status.textContent = '';
} catch (err) {
status.textContent = `Error: ${err.message}`;
}
}AbortController — Request Timeout
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch('/api/data', { signal: controller.signal });
clearTimeout(timeout);
return await res.json();
} catch (err) {
if (err.name === 'AbortError') console.log('Request timed out');
}Use AbortController to cancel stale requests — for example when a user types quickly in a search field and only the last request should render.
