XMLHttpRequest, or XHR for short, is a built-in browser object that lets us exchange data with a server behind the scenes, without having to reload the entire page. This is the core technology behind AJAX.

Think of it like this: When you scroll on Twitter and new tweets load, the whole page doesn't refresh. This is done using techniques like XHR or its more modern alternatives.


⚙️ The Main XHR Workflow

Working with XHR always follows a 4-step cycle:

1 - Create the Object: First, we need to create a new instance.

const xhr = new XMLHttpRequest();

2 - Open the Request (open): Here, we specify the request method (e.g., GET or POST) and the server's URL.

// method, URL, and whether it should be asynchronous (almost always true)
xhr.open("GET", "<https://api.example.com/data>", true);

3 - Listen for State Changes (onreadystatechange): This is an event handler. Every time the request's state changes, this function runs, letting us know the status of our request.

xhr.onreadystatechange = function() {
  // I'll explain the code for this part below
};

4 - Send the Request (send): This command actually fires the request off to the server.

xhr.send();

📥 Fetching Data with GET (Full Example)

A GET request is used to retrieve information from a server. Inside the onreadystatechange event, we check for two important things:

const xhr = new XMLHttpRequest();
const url = "<https://jsonplaceholder.typicode.com/todos/1>";

xhr.open("GET", url, true);

xhr.onreadystatechange = function () {
  // Is the request finished and successful?
  if (xhr.readyState === 4 && xhr.status === 200) {
    // xhr.responseText contains the server's response as a string
    console.log("Response from server:", xhr.responseText);
    
    // We can parse the JSON string into a JavaScript object
    const data = JSON.parse(xhr.responseText);
    console.log("Title of To-Do:", data.title);
  } else if (xhr.readyState === 4) {
    // If the request is finished but was not successful
    console.error("Error:", xhr.status, xhr.statusText);
  }
};

xhr.send();

📤 Sending Data with POST

When we want to send data to a server (like form information), we use a POST request.

const xhr = new XMLHttpRequest();
const url = "<https://jsonplaceholder.typicode.com/posts>";

xhr.open("POST", url, true);

// Tell the server we're sending JSON data
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 201) { // 201 means "Created"
    console.log("Server response:", xhr.responseText);
  } else if (xhr.readyState === 4) {
    console.error("Error:", xhr.status, xhr.statusText);
  }
};

const newPost = {
  title: 'foo',
  body: 'bar',
  userId: 1,
};

// Convert the JavaScript object to a JSON string and send it
xhr.send(JSON.stringify(newPost));

⚠️ Hacker's Tip: Should We Still Use XHR?

Short answer: Rarely.

XMLHttpRequest is a powerful technology, but it's old and a bit complicated to work with (especially the onreadystatechange part).

Today, modern JavaScript uses the Fetch API, which is much simpler and works with Promises.