AJAX XMLHttp
XMLHttpRequest (XHR) is the original AJAX engine. Modern code uses fetch instead — but XHR is still useful for upload progress events and supporting very old browsers.
The classic shape
JS
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/users"); // method, url, [async = true]
xhr.responseType = "json"; // also "text", "blob", "arraybuffer", "document"
xhr.setRequestHeader("Accept", "application/json");
xhr.addEventListener("load", () => {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
} else {
console.error("HTTP", xhr.status);
}
});
xhr.addEventListener("error", () => console.error("Network error"));
xhr.send();
What XHR still does better than fetch
| Need | Why XHR wins |
|---|---|
| Upload progress events | xhr.upload.onprogress — fetch needs streaming readers. |
| Synchronous request (legacy) | open(…, false). Almost always a bad idea — blocks the UI. |
| Tight control over partial reads | You can read responseText as it streams. |
The state machine
| readyState | Means |
|---|---|
| 0 UNSENT | Created, not opened. |
| 1 OPENED | open() called. |
| 2 HEADERS_RECEIVED | Response headers in. |
| 3 LOADING | Body streaming. |
| 4 DONE | Finished — success or error. |
Upload progress example
JS
const xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
const pct = (e.loaded / e.total) * 100;
bar.style.width = `${pct}%`;
}
});
xhr.send(new FormData(form));
Tip: Default to
fetch. Reach for XHR only for upload progress bars or rare legacy use cases — the codebase will be cleaner.Example
Example
<!DOCTYPE html>
<html>
<body>
<p id="out"></p>
<script>
document.getElementById("out").textContent = "Hello from AJAX XMLHttp!";
</script>
</body>
</html>
Try it Yourself »
Exercise
Create the legacy AJAX object.
const xhr = new
();
A long all-caps then camelCase name.
Discussion
Loading…