Chapter 23: AJAX XMLHttp
1. What is the XMLHttpRequest Object?
XMLHttpRequest (usually abbreviated XHR) is a built-in browser API — it is not a library or framework — it is part of the browser itself.
It allows JavaScript code running in the browser to:
- Make HTTP requests to a server
- Do this in the background (asynchronously)
- Receive the response
- Update the current web page without reloading the entire page
This is the core technology that made AJAX possible.
Important historical note (you should know this):
- Created by Microsoft for Internet Explorer 5 in 1999 (originally called XMLHTTP)
- Became standard across all browsers around 2005–2006
- The name contains “XML” because originally it was mostly used to receive XML data
- Today almost nobody uses it for XML — most use JSON, but the name never changed
So when people say “XMLHttpRequest”, they usually just mean “the object that lets JavaScript talk to the server in the background”.
2. Why was XMLHttpRequest revolutionary?
Before XHR:
- Every interaction with the server (clicking a link, submitting a form, changing a dropdown…) → full page reload
- Slow, especially on dial-up / early broadband
- Lost scroll position, form data, etc.
With XMLHttpRequest:
- You can send small requests (e.g. “check if username is available”, “get new messages”, “load more products”)
- Get back only the needed data
- Update only part of the page → Feels fast, modern, smooth
This is what made Gmail, Google Maps, Facebook news feed, Twitter (early version), online spreadsheets, etc. feel magical around 2005–2010.
3. The Life Cycle of an XMLHttpRequest (very important)
Every XHR request goes through these readyState stages:
| readyState value | Constant name | Meaning |
|---|---|---|
| 0 | UNSENT | Object created, but open() not called yet |
| 1 | OPENED | open() was called, but send() not yet |
| 2 | HEADERS_RECEIVED | send() called, headers and status received |
| 3 | LOADING | Downloading response body (partial data available) |
| 4 | DONE | Request finished (success or failure) |
Most people only care about readyState 4 + HTTP status 200–299.
4. Basic Structure – Step by Step (classic style)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// Step 1: Create the object let xhr = new XMLHttpRequest(); // Step 2: Configure the request xhr.open(method, url, async); // Step 3: (optional) Set request headers xhr.setRequestHeader("Content-Type", "application/json"); xhr.setRequestHeader("Authorization", "Bearer your-token"); // Step 4: Define what happens when we get a response xhr.onload = function() { // This runs when readyState === 4 if (xhr.status >= 200 && xhr.status < 300) { // Success console.log("Response:", xhr.responseText); } else { // Server error (404, 500, etc.) console.log("Error:", xhr.status, xhr.statusText); } }; // Step 5: Handle network-level errors xhr.onerror = function() { console.log("Network error – cannot reach server"); }; // Step 6: (optional) Track progress xhr.onprogress = function(event) { if (event.lengthComputable) { let percent = (event.loaded / event.total) * 100; console.log(`Loaded ${percent.toFixed(1)}%`); } }; // Step 7: Send the request xhr.send(); // for GET // xhr.send(data); // for POST/PUT with body |
5. Realistic Example 1 – GET request (classic style)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>AJAX – XMLHttpRequest Example</title> <style> body { font-family: Arial; margin: 40px; } button { padding: 12px 24px; font-size: 16px; margin-right: 10px; } #result { margin-top: 30px; padding: 20px; background: #f8f9fa; border: 1px solid #ccc; border-radius: 8px; min-height: 120px; } </style> </head> <body> <h2>XMLHttpRequest – Classic GET Example</h2> <button onclick="getServerTime()">Get Server Time</button> <button onclick="getRandomQuote()">Get Random Quote</button> <button onclick="getUserInfo()">Get Fake User Info</button> <div id="result">Click one of the buttons above…</div> <script> function sendRequest(url, callback) { const xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { callback(null, xhr.responseText); } else { callback(`Error ${xhr.status}: ${xhr.statusText}`, null); } }; xhr.onerror = function() { callback("Network error", null); }; xhr.send(); } function getServerTime() { sendRequest("https://httpbin.org/anything", (err, data) => { if (err) { document.getElementById("result").innerHTML = `<strong>Error:</strong> ${err}`; return; } document.getElementById("result").innerHTML = ` <strong>Server response:</strong><br> <pre>${data}</pre> `; }); } function getRandomQuote() { sendRequest("https://api.quotable.io/random", (err, data) => { if (err) { document.getElementById("result").innerHTML = `<strong>Error:</strong> ${err}`; return; } const quote = JSON.parse(data); document.getElementById("result").innerHTML = ` <strong>Quote:</strong> ${quote.content}<br> <strong>— ${quote.author}</strong> `; }); } function getUserInfo() { sendRequest("https://randomuser.me/api/", (err, data) => { if (err) { document.getElementById("result").innerHTML = `<strong>Error:</strong> ${err}`; return; } const user = JSON.parse(data).results[0]; document.getElementById("result").innerHTML = ` <strong>Name:</strong> ${user.name.first} ${user.name.last}<br> <strong>Email:</strong> ${user.email}<br> <strong>Country:</strong> ${user.location.country} `; }); } </script> </body> </html> |
6. Key Properties & Events of XMLHttpRequest
| Property / Event | What it contains / when it fires | Typical usage |
|---|---|---|
| xhr.readyState | 0–4 (see table above) | Usually wait for === 4 |
| xhr.status | HTTP status code (200, 404, 500…) | Success = 200–299 |
| xhr.statusText | “OK”, “Not Found”, etc. | Show in error messages |
| xhr.responseText | Response as plain string | Most common when expecting JSON/text |
| xhr.responseXML | Parsed XML document (if server sent text/xml) | Used when really dealing with XML |
| xhr.response | Depends on responseType (text, json, blob…) | Modern usage |
| xhr.onload | Fires when request is complete (readyState 4) | Main success handler |
| xhr.onerror | Fires on network failure (no internet, CORS…) | Handle connection problems |
| xhr.onprogress | Progress events during download | Show progress bars |
7. Quick Summary – XMLHttpRequest Cheat Sheet
| Step | Code example |
|---|---|
| Create | new XMLHttpRequest() |
| Configure | xhr.open(“GET”, url, true) |
| Set headers | xhr.setRequestHeader(“Accept”, “application/json”) |
| Handle response | xhr.onload = function() { … } |
| Handle error | xhr.onerror = function() { … } |
| Send | xhr.send() or xhr.send(JSON.stringify(data)) |
| Get data | xhr.responseText or xhr.response |
8. Modern Advice (2025–2026)
- Use fetch + async/await for new code — much cleaner
- Know XMLHttpRequest because:
- You will see it in old tutorials
- You will find it in legacy code
- Some very specific features (upload progress with xhr.upload, older CORS tricks) are easier with XHR
- Many libraries (some chart libraries, file upload components) still use it internally
Would you like to continue with one of these next?
- Full POST request example with form data
- Upload progress bar using XMLHttpRequest
- How to parse XML response when the server still returns XML
- Comparison: XMLHttpRequest vs fetch vs axios
- Handling CORS errors (very common issue)
- Making AJAX look like old-school (loading spinner, error messages)
Just tell me what you want to practice or understand more deeply! 😊
