Loading...
Loading...
Make HTTP requests. Talk to servers. Get and send data.
Browsers and servers spend most of their time waiting — for network responses, timers, and user input. Async JavaScript lets your program stay responsive while work happens in the background using callbacks, Promises, and async/await.
The Fetch API is the browser-native way to talk to servers — GET and POST requests, reading JSON, setting headers, and handling HTTP errors without jQuery or axios.
Synchronous code runs one line at a time. But real applications wait for network requests, file reads, and timers. Async JavaScript lets your program keep running while that work happens in the background — without freezing the UI.
This module covers the full async story: callbacks, Promises, async/await, and the Fetch API. Visual timelines show when tasks enter the queue, when they resolve, and why async/await is syntactic sugar over Promises — not magic.
Every web app loads remote data. Fetch is how you authenticate, submit forms, and hydrate React state. Misreading response.ok, forgetting to parse JSON, or ignoring network errors causes silent failures users blame on your UI.
The simplest way to make HTTP requests in JavaScript.
// fetch() returns a Promise: const response = await fetch("https://api.example.com/users"); const users = await response.json(); console.log(users);
fetch() makes an HTTP request and returns a Promise that resolves to a Response object. .json() parses the body as JSON (also returns a Promise).
What fetch() gives you back.
const res = await fetch("/api/data"); // Properties: res.ok; // true if status 200-299 res.status; // 200, 404, 500, etc. res.statusText; // "OK", "Not Found", etc. res.headers; // Headers object res.url; // final URL (after redirects) res.redirected; // true if redirected // Body methods (each can only be called ONCE): const json = await res.json(); // parse as JSON const text = await res.text(); // parse as text const blob = await res.blob(); // parse as Blob const buffer = await res.arrayBuffer(); // raw bytes const form = await res.formData(); // parse as FormData
Common status codes:
Send data to the server.
// POST with JSON body: const response = await fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ name: "Alice", email: "alice@example.com" }), }); const newUser = await response.json(); console.log(newUser.id); // server-assigned ID
// PUT (update entire resource): await fetch(`/api/users/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Bob", email: "bob@test.com" }), }); // PATCH (partial update): await fetch(`/api/users/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Bob Updated" }), }); // DELETE: await fetch(`/api/users/${id}`, { method: "DELETE", });
Configure requests with headers, credentials, cache, and more.
// Full fetch options: const response = await fetch(url, { method: "POST", // GET, POST, PUT, PATCH, DELETE headers: { "Content-Type": "application/json", "Authorization": "Bearer <token>", "X-Custom-Header": "value", }, body: JSON.stringify(data), // request body credentials: "include", // send cookies cross-origin cache: "no-store", // bypass cache mode: "cors", // cors, no-cors, same-origin signal: controller.signal, // for aborting });
// Working with Headers object: const headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("Authorization", "Bearer token123"); // Reading response headers: const res = await fetch(url); res.headers.get("Content-Type"); // "application/json" res.headers.has("X-Custom"); // true/false // Send form data (browser sets Content-Type automatically): const formData = new FormData(); formData.append("file", fileInput.files[0]); formData.append("name", "document.pdf"); await fetch("/api/upload", { method: "POST", body: formData, // no Content-Type header needed! });
Cancel in-flight requests.
// Create a controller: const controller = new AbortController(); // Pass its signal to fetch: fetch("/api/large-data", { signal: controller.signal }) .then(res => res.json()) .then(data => display(data)) .catch(err => { if (err.name === "AbortError") { console.log("Request was cancelled"); } else { throw err; // real error } }); // Cancel the request: controller.abort(); // triggers AbortError
// Practical: timeout after 5 seconds async function fetchWithTimeout(url, ms = 5000) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), ms); try { const res = await fetch(url, { signal: controller.signal }); return await res.json(); } finally { clearTimeout(timeout); } } // Practical: cancel on component unmount (React) useEffect(() => { const controller = new AbortController(); fetch("/api/data", { signal: controller.signal }) .then(res => res.json()) .then(setData); return () => controller.abort(); // cleanup }, []);
Common questions about fetch api.