JavaScript: The Fetch API and AbortController
The fetch() API is the modern, promise-based standard for making HTTP requests in the browser, completely replacing legacy XMLHttpRequest (AJAX).
While basic fetching is simple, interviewers want to know if you can handle edge cases: network failures, non-200 HTTP statuses, and race conditions.
1. The Basic Fetch Pipeline
fetch() returns a Promise that resolves to the Response object representing the entire HTTP response. To extract the actual JSON data, you must call a secondary asynchronous method like .json().
async function getUser() {
try {
const response = await fetch("https://api.example.com/user");
// Extract JSON payload
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Network failure:", error);
}
}2. The fetch Error Handling Pitfall
A common "gotcha" in interviews is error handling.
Unlike libraries like Axios, fetch() only rejects its Promise if there is a fundamental network failure (like DNS lookup failure, or the user losing internet).
If the server returns an HTTP error code (e.g., 404 Not Found or 500 Internal Server Error), fetch() will not reject the promise. It resolves normally, leaving it up to you to manually verify the response.ok boolean property.
The Correct Way to Handle Errors
async function getRobustUser() {
try {
const response = await fetch("https://api.example.com/user");
// Manually check if HTTP status is 200-299
if (!response.ok) {
throw new Error(`HTTP Error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
// Catches BOTH network failures AND our thrown HTTP errors
console.error("Request failed:", error.message);
}
}3. Canceling Requests with AbortController
In single-page applications (like React), users navigate quickly. If a user triggers a data fetch on "Page A", but quickly navigates to "Page B", the fetch from Page A is still running in the background. When it finally resolves, it might try to update UI state for a component that no longer exists, causing memory leaks and UI race conditions.
To fix this, you must cancel the ongoing fetch request using an AbortController.
How to use AbortController:
- Create an instance of
AbortController. - Extract the
signalproperty. - Pass the
signalinto thefetchoptions object. - Call
controller.abort()when you want to terminate the request.
// 1. Initialize controller
const controller = new AbortController();
async function fetchData() {
try {
// 2. Pass the signal to fetch
const response = await fetch("https://api.slow.com/data", {
signal: controller.signal
});
const data = await response.json();
console.log(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log("Fetch was successfully cancelled by the user.");
} else {
console.error("Fetch failed:", error);
}
}
}
fetchData();
// 3. User clicks "Cancel" button, or navigates away
document.getElementById('cancel-btn').addEventListener('click', () => {
controller.abort(); // Terminates the fetch immediately!
});Senior-Level Interview Answer
The native
fetch()API provides a modern, Promise-based interface for executing HTTP requests. Its primary architectural quirk is that the returned Promise only rejects on complete network failure; HTTP error statuses (like 400 or 500) resolve normally. Therefore, robust implementation requires manually asserting theresponse.okproperty before parsing the payload. Furthermore, because asynchronous requests can cause race conditions or memory leaks in SPA environments if components unmount before resolution,fetchintegrates with the DOMAbortControllerAPI. By passing anAbortSignalto the fetch options, developers can programmatically terminate in-flight requests, gracefully catching the resultingAbortError.
Common Interview Mistakes
❌ Assuming fetch() fails on 404
If an interviewer provides a code snippet of a fetch call to an endpoint that returns a 500 Server Error and asks "What does the console log in the catch block?", the answer is Nothing. The code proceeds to .json() and likely crashes there trying to parse HTML error pages as JSON.
❌ Misunderstanding when to use .json() vs .text()
Candidates often reflexively call .json() on every fetch response. If an API returns plain text, HTML, or an empty 204 No Content body, .json() will throw a syntax error. Always verify the Content-Type headers or know the expected API structure.
