Note: Fetch doesn't reject on HTTP errors (404, 500) - check response.ok or response.status. Body can only be read once - use response.clone() if you need to read it multiple times. Default credentials: "same-origin" doesn't send cookies to different origins.
2. Fetch API Advanced Patterns (AbortController, Streams)
Feature
Syntax
Description
Use Case
AbortController
new AbortController()
Creates controller for aborting fetch requests. Has signal property and abort() method.
Cancel requests
signal
controller.signal
AbortSignal to pass to fetch. Automatically aborts when controller.abort() called.
Link abort to fetch
abort()
controller.abort(reason)
Aborts associated request. Optional reason passed to error handler.
Trigger cancellation
ReadableStream
response.body
Response body as ReadableStream. Allows progressive reading of large responses.
Stream large data
getReader()
stream.getReader()
Gets ReadableStreamDefaultReader to read chunks. Locks stream.
Read stream chunks
read()
reader.read()
Returns Promise<{value, done}>. Value is Uint8Array chunk.
// Stream large file download with progressasync function downloadWithProgress(url) { const response = await fetch(url); const contentLength = response.headers.get("content-length"); const total = parseInt(contentLength, 10); let loaded = 0; const reader = response.body.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); loaded += value.length; const progress = (loaded / total) * 100; console.log(`Progress: ${progress.toFixed(2)}%`); } // Concatenate chunks into single Uint8Array const chunksAll = new Uint8Array(loaded); let position = 0; for (let chunk of chunks) { chunksAll.set(chunk, position); position += chunk.length; } return chunksAll;}// Stream text data line by lineasync function streamText(url) { const response = await fetch(url); const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const text = decoder.decode(value, { "stream": true }); console.log("Chunk:", text); }}
Example: Advanced patterns
// Request deduplicationconst requestCache = new Map();async function fetchOnce(url) { if (requestCache.has(url)) { return requestCache.get(url); } const promise = fetch(url).then((r) => r.json()); requestCache.set(url, promise); try { return await promise; } catch (error) { requestCache.delete(url); // Remove failed request throw error; }}// Retry with exponential backoffasync function fetchWithRetry(url, options = {}, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url, options); if (!response.ok && i < maxRetries - 1) { throw new Error(`HTTP ${response.status}`); } return response; } catch (error) { if (i === maxRetries - 1) throw error; const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s await new Promise((resolve) => setTimeout(resolve, delay)); } }}// Parallel requests with Promise.allasync function fetchMultiple(urls) { const promises = urls.map((url) => fetch(url).then((r) => r.json()) ); return Promise.all(promises);}// Race condition - first to respond winsasync function fetchFastest(urls) { const promises = urls.map((url) => fetch(url).then((r) => r.json()) ); return Promise.race(promises);}
Warning:AbortController.abort() throws an error in the fetch promise - always catch it. Streams can only be read once - lock is not released until reader is closed. When streaming, make sure to handle errors and cleanup properly to avoid memory leaks.
3. XMLHttpRequest and Legacy AJAX Patterns
Property/Method
Description
Modern Alternative
new XMLHttpRequest()
Creates XHR object for AJAX requests
Use fetch()
open(method, url, async)
Initializes request. Third parameter is async flag (default true).
fetch(url, {method})
send(body)
Sends request. Body for POST/PUT.
fetch(url, {body})
abort()
Aborts request in progress
AbortController
setRequestHeader(name, value)
Sets HTTP request header. Call after open(), before send().
// GET requestconst xhr = new XMLHttpRequest();xhr.open("GET", "/api/users", true);xhr.onload = function() { if (xhr.status === 200) { const data = JSON.parse(xhr.responseText); console.log("Success:", data); } else { console.error("Error:", xhr.status); }};xhr.onerror = function() { console.error("Network error");};xhr.send();// POST request with JSONconst xhr2 = new XMLHttpRequest();xhr2.open("POST", "/api/users", true);xhr2.setRequestHeader("Content-Type", "application/json");xhr2.onreadystatechange = function() { if (xhr2.readyState === 4) { // DONE if (xhr2.status === 201) { console.log("Created:", JSON.parse(xhr2.responseText)); } }};xhr2.send(JSON.stringify({ "name": "John" }));// Upload with progressconst formData = new FormData();formData.append("file", file);const xhr3 = new XMLHttpRequest();xhr3.upload.addEventListener("progress", (event) => { if (event.lengthComputable) { const percent = (event.loaded / event.total) * 100; console.log(`Upload: ${percent.toFixed(2)}%`); }});xhr3.open("POST", "/api/upload", true);xhr3.send(formData);
Note: XMLHttpRequest is legacy API - use Fetch API for new projects. XHR still useful for upload progress tracking (Fetch doesn't support this natively yet). XHR requires more boilerplate code and callback-based error handling compared to Promise-based Fetch.
4. WebSocket API for Real-time Communication
Feature
Syntax
Description
Browser Support
WebSocket Constructor
new WebSocket(url, protocols)
Creates WebSocket connection. URL must start with ws:// or wss://. Optional protocols array.
All Browsers
send(data)
ws.send(data)
Sends data to server. Accepts string, Blob, ArrayBuffer, ArrayBufferView.
All Browsers
close(code, reason)
ws.close(code, reason)
Closes connection. Optional close code and reason string.
All Browsers
Property
Type
Description
Values
readyState
number
Connection state
0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED
url
string
WebSocket URL
Read-only
protocol
string
Negotiated subprotocol
Read-only
bufferedAmount
number
Bytes queued but not yet transmitted
Read-only
binaryType
string
Binary data type received
"blob" or "arraybuffer"
Event
Description
Event Object Properties
open
Connection established successfully
Standard Event object
message
Message received from server
data: message content (string, Blob, ArrayBuffer)
error
Error occurred
Standard Event object
close
Connection closed
code: close code, reason: close reason, wasClean: boolean
Example: WebSocket basic usage
// Create WebSocket connectionconst ws = new WebSocket("wss://example.com/socket");// Connection openedws.addEventListener("open", (event) => { console.log("Connected to server"); ws.send("Hello Server!");});// Listen for messagesws.addEventListener("message", (event) => { console.log("Message from server:", event.data); // Handle different data types if (typeof event.data === "string") { const message = JSON.parse(event.data); handleMessage(message); } else if (event.data instanceof Blob) { // Handle binary data event.data.text().then((text) => console.log(text)); }});// Handle errorsws.addEventListener("error", (event) => { console.error("WebSocket error:", event);});// Connection closedws.addEventListener("close", (event) => { console.log("Connection closed:", event.code, event.reason); if (event.wasClean) { console.log("Clean close"); } else { console.log("Connection died"); }});// Send different data typesws.send("Text message");ws.send(JSON.stringify({ "type": "chat", "message": "Hello" }));ws.send(new Blob(["binary data"]));ws.send(new Uint8Array([1, 2, 3, 4]));// Close connection gracefullyws.close(1000, "Normal closure");
Note: Always use wss:// (secure WebSocket) in production, not ws://. Check readyState before calling send() to avoid errors. Implement reconnection logic for production applications. Use bufferedAmount to check if send buffer is full.
5. Server-Sent Events (EventSource) API
Feature
Syntax
Description
Browser Support
EventSource Constructor
new EventSource(url, options)
Creates server-sent events connection. One-way: server to client only.
Note: EventSource automatically reconnects on connection loss (WebSocket doesn't). SSE is one-way only (server to client) - use WebSocket for bidirectional communication. SSE uses regular HTTP, works through most proxies and firewalls. Default retry timeout is 3 seconds.
6. Navigator.sendBeacon for Analytics
Feature
Syntax
Description
Browser Support
sendBeacon
navigator.sendBeacon(url, data)
Sends asynchronous POST request that completes even if page is unloading. Returns boolean indicating if queued successfully.
Note:sendBeacon is designed for analytics and diagnostics that must not be lost when page unloads. Request completes even if user closes tab/window. Cannot read response or handle errors. Has size limits (typically 64KB). Uses POST method only.
Warning: Don't use sendBeacon for critical data that requires confirmation - there's no way to know if request succeeded. Browsers may limit total beacon data size. Use Blob with proper Content-Type for JSON data, not plain string.
Network Communication Best Practices
Use Fetch API for modern HTTP requests - cleaner syntax and Promise-based
Always check response.ok or response.status - fetch doesn't reject on HTTP errors
Use AbortController for request cancellation and timeouts
Implement proper error handling with try/catch for async/await patterns
Use WebSocket for bidirectional real-time communication (chat, live updates)
Use EventSource for one-way server-to-client streaming (notifications, live feeds)
Implement reconnection logic for WebSocket connections in production
Use credentials: "include" to send cookies with cross-origin requests
Use navigator.sendBeacon for analytics during page unload - guaranteed delivery
Stream large responses with ReadableStream for memory efficiency and progress tracking