JS AJAX XMLHttp
In this page:
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// this.responseText
}
};
xhr.open("GET", url);
xhr.send();
Creating and Configuring a Request
new XMLHttpRequest() creates a new request object, and .open(method, url, async) configures it with an HTTP method, target URL, and whether it should run asynchronously (almost always true in modern code) -- configuration only, nothing is sent yet at this point.
Example: Creating and Configuring a Request
const xhr = new XMLHttpRequest();
xhr.open("GET", "data.php", true); // configured, nothing sent yet
console.log(xhr.readyState); // 1 - opened
The readyState Lifecycle
readyState progresses through five numeric values as a request proceeds: 0 (uninitialized), 1 (opened), 2 (headers received), 3 (loading), and 4 (done) -- the onreadystatechange event fires each time this value changes, letting you react at any stage, though checking specifically for 4 is the most common pattern.
Example: The readyState Lifecycle
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
const xhr = new XMLHttpRequest();
// Assign `() => console.log("readyState:", xhr.readyState)` to `xhr.onreadystatechange`
// Assign `() => console.log("readyState:", xhr.readyState)` to `xhr.onreadystatechange`
xhr.onreadystatechange = () => console.log("readyState:", xhr.readyState);
// Call `xhr.open("GET", "data.php")`
// Call `xhr.open("GET", "data.php")`
xhr.open("GET", "data.php");
// Call `xhr.send()`
// Call `xhr.send()`
xhr.send();
Checking the HTTP Status Code
Once readyState reaches 4, the status property holds the actual HTTP status code returned by the server -- 200 for success, 404 for not found, 500 for a server error -- and checking it alongside readyState is essential to distinguish a truly successful response from a completed-but-failed one.
Example: Checking the HTTP Status Code
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
const xhr = new XMLHttpRequest();
// Assign `() => {` to `xhr.onreadystatechange`
// Assign `() => {` to `xhr.onreadystatechange`
xhr.onreadystatechange = () => {
// Check whether `xhr.readyState === 4`
// Check whether `xhr.readyState === 4`
if (xhr.readyState === 4) {
// Print `xhr.status === 200 ? "Success" : "Failed with status " + xhr.status` to the console
// Print `xhr.status === 200 ? "Success" : "Failed with status " + xhr.status` to the console
console.log(xhr.status === 200 ? "Success" : "Failed with status " + xhr.status);
}
};
// Call `xhr.open("GET", "data.php")`
// Call `xhr.open("GET", "data.php")`
xhr.open("GET", "data.php");
// Call `xhr.send()`
// Call `xhr.send()`
xhr.send();
Sending the Request and Handling Errors
.send() actually transmits the configured request -- with an optional body argument for POST/PUT requests -- and separate onload/onerror event handlers (a somewhat more modern addition to XMLHttpRequest) offer a cleaner alternative to manually checking readyState for basic success/failure handling.
Example: Sending the Request and Handling Errors
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
const xhr = new XMLHttpRequest();
// Assign `() => console.log("Loaded:", xhr.responseText)` to `xhr.onload`
// Assign `() => console.log("Loaded:", xhr.responseText)` to `xhr.onload`
xhr.onload = () => console.log("Loaded:", xhr.responseText);
// Assign `() => console.log("Request failed")` to `xhr.onerror`
// Assign `() => console.log("Request failed")` to `xhr.onerror`
xhr.onerror = () => console.log("Request failed");
// Call `xhr.open("GET", "data.php")`
// Call `xhr.open("GET", "data.php")`
xhr.open("GET", "data.php");
// Call `xhr.send()`
// Call `xhr.send()`
xhr.send();
XMLHttpRequest vs fetch: A Direct Comparison
Placing the same GET request side by side highlights fetch's advantage clearly: fewer lines, no manual readyState checking, and native promise chaining -- the reason fetch has become the default recommendation for new code, while XMLHttpRequest knowledge remains useful mainly for legacy code.
Example: XMLHttpRequest vs fetch: A Direct Comparison
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
// Declare the constant `xhr` as a new `XMLHttpRequest` instance
const xhr = new XMLHttpRequest();
// Assign `() => console.log(xhr.responseText)` to `xhr.onload`
// Assign `() => console.log(xhr.responseText)` to `xhr.onload`
xhr.onload = () => console.log(xhr.responseText);
// Call `xhr.open("GET", "data.php")`
// Call `xhr.open("GET", "data.php")`
xhr.open("GET", "data.php");
// Call `xhr.send()`
// Call `xhr.send()`
xhr.send();
// Call `fetch("data.php").then(r => r.text()).then(text => console.log(text))`
// Call `fetch("data.php").then(r => r.text()).then(text => console.log(text))`
fetch("data.php").then(r => r.text()).then(text => console.log(text));
- Checking readyState without also checking status, which can trigger the completion handler on a failed request (like a 404) as if it succeeded.
- Calling .open() with the wrong argument order or forgetting to call .send() afterward, leaving the request configured but never actually sent.
- Setting request headers with .setRequestHeader() before calling .open(), when it must be called after open() but before send().
- new XMLHttpRequest() creates a request object, .open(method, url) configures it, and .send() actually fires it off.
- readyState tracks the request's lifecycle stage from 0 (uninitialized) to 4 (complete), typically checked inside onreadystatechange.
- status holds the HTTP status code (like 200 or 404) once the response arrives, and should be checked alongside readyState.
XMLHttpRequest has been supported in every browser since the early 2000s and remains supported today for backward compatibility.
Chapter Quiz — Complete all 26 topics to unlock
0/26 topics done
Complete these topics first:
- JS JSON
- JS Regular Expressions
- JS Fetch API
- JS LocalStorage and SessionStorage
- JS Cookies
- JS setTimeout and setInterval
- JS Event Loop
- JS Web Workers
- JS Service Workers
- JS AJAX
- JS AJAX Intro
- JS AJAX XMLHttp
- JS AJAX Request
- JS AJAX Response
- JS AJAX XML
- JS AJAX PHP
- JS AJAX Database
- JS JSONP
- JS RegExp Flags
- JS RegExp Classes
- JS RegExp Metachars
- JS RegExp Assertions
- JS RegExp Groups
- JS RegExp Quantifiers
- JS JSON HTML
- JS JSON vs XML