Before AJAX existed, every interaction that needed server data caused a full page reload. Click a button, wait for the whole page to reload, see the result. AJAX broke that pattern by letting JavaScript send requests to the server in the background and update only the part of the page that changed.
The name stands for Asynchronous JavaScript and XML, but almost nobody uses XML anymore. Today it means any technique where JavaScript fetches data from a server without navigating away from the current page. The modern tool for this is the Fetch API.
AJAX is not a library or a framework. It is a browser capability. Every modern browser can send HTTP requests from JavaScript. React, Vue, Angular, and every frontend framework ultimately relies on it to talk to APIs.
In the early web, every form submission or data request meant the browser sent a request to the server, the server responded with a complete HTML page, and the browser rendered the whole thing from scratch. If you were filling out a form and wanted to check if a username was available, you had to submit the form, wait for the page to reload, and see the validation result.
Google Maps in 2005 demonstrated something different — you could drag the map and new tiles would load smoothly without any page reload. Gmail showed that emails could appear without the page refreshing. These used a browser feature called XMLHttpRequest that had been available since 1999 but was not widely used.
Jesse James Garrett named this pattern "AJAX" in 2005. The core idea: JavaScript can send an HTTP request, wait for the response in the background, and update only the part of the page that needs changing. Everything else stays intact.
When JavaScript makes an AJAX request, it creates an HTTP request object (XMLHttpRequest or fetch), sends it to a URL, and provides a callback or Promise to handle the response. The browser sends the request in the background while the main thread keeps running.
The response can be anything the server sends — JSON, HTML fragments, plain text, binary data. In modern applications it is almost always JSON, which JavaScript can parse directly into objects and arrays.
// Fetch user data and display it without reloading the page
async function loadUserProfile(userId) {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
// Always check this — fetch() only rejects on network failure,
// not on HTTP errors like 404 or 500
throw new Error(`Server returned ${response.status}`);
}
const user = await response.json();
// Update only the profile section — rest of page unchanged
document.getElementById('user-name').textContent = user.name;
document.getElementById('user-email').textContent = user.email;
}
loadUserProfile(42).catch(err => {
document.getElementById('error-msg').textContent = 'Could not load profile.';
});
// You will see this in older codebases — use fetch() for new code
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/users/42');
xhr.onload = function () {
if (xhr.status === 200) {
const user = JSON.parse(xhr.responseText);
document.getElementById('user-name').textContent = user.name;
} else {
console.error('Request failed:', xhr.status);
}
};
xhr.onerror = function () {
console.error('Network error');
};
xhr.send();
In a traditional web app, clicking "Add to Cart" sends a POST request, the server processes it, and the server sends back a complete HTML page. Your scroll position resets, the browser re-renders everything, and any unsaved form input is lost.
With AJAX, clicking "Add to Cart" sends a POST request in the background. The server responds with a small JSON object like {"cartCount": 3}. JavaScript updates just the cart icon number. You stay where you are on the page.
| Scenario | Traditional (Full Reload) | AJAX (Partial Update) |
|---|---|---|
| Add item to cart | Full page reload, scroll resets | Cart count updates, stay on page |
| Check username availability | Submit form, wait for reload | Instant feedback as you type |
| Load more posts | Navigate to page 2 | Posts append below existing ones |
| Search autocomplete | Not possible without reload | Suggestions appear instantly |
| Like / upvote | Page reload to confirm | Count updates instantly |
GET requests retrieve data. POST requests send data. AJAX works with both. Here is a typical pattern for submitting a form without reloading the page:
async function submitContactForm(event) {
event.preventDefault(); // Stop the default form reload
const form = event.target;
const data = {
name: form.name.value,
email: form.email.value,
message: form.message.value,
};
try {
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data), // Must stringify — cannot send plain object
});
if (!response.ok) throw new Error('Submission failed');
const result = await response.json();
document.getElementById('form-status').textContent = result.message;
form.reset();
} catch (err) {
document.getElementById('form-status').textContent = 'Something went wrong. Please try again.';
}
}
document.getElementById('contact-form').addEventListener('submit', submitContactForm);
When your JavaScript on example.com tries to fetch data from api.otherdomain.com, the browser blocks it by default. This is the Same-Origin Policy — a security rule that prevents malicious sites from making requests on behalf of users.
The server at api.otherdomain.com must explicitly allow cross-origin requests using CORS headers. If it does not, the browser blocks the response. The fix is server-side — the API must send the correct Access-Control-Allow-Origin header.
During development, if you run a frontend on localhost:3000 and an API on localhost:8080, that is still a cross-origin request and requires CORS configuration. This catches almost every beginner who sets up a separate frontend and backend.
Use the Fetch API for all new code. It returns Promises, works cleanly with async/await, and has a much more readable API. XMLHttpRequest is callback-based and verbose.
One gotcha with fetch: it does not reject on HTTP errors. A 404 or 500 response resolves the Promise normally. You must check response.ok yourself. This trips up almost everyone coming from jQuery or Axios which throw on non-2xx responses.
These are the things that consistently confuse developers learning AJAX for the first time.
These are the AJAX questions that come up most often in frontend developer interviews.
Try this next
0 of 5 completed
Yes. React, Vue, and Angular all use fetch() or axios under the hood to talk to APIs. Understanding AJAX means understanding what these frameworks are doing for you. When something breaks, you need to know what is happening at the HTTP level.
Almost certainly a CORS issue. Postman does not enforce the Same-Origin Policy. The browser blocks the response because the server did not include the Access-Control-Allow-Origin header. Fix it server-side.
fetch() works without any dependencies. Axios adds automatic JSON parsing, throws on HTTP errors by default, and has interceptors for auth tokens. For simple use cases, fetch() is fine. For larger apps, Axios saves boilerplate.
Explore 500+ free tutorials across 20+ languages and frameworks.