Sitemap

The history of XMLHttpRequest (XHR)

5 min readNov 23, 2018
Press enter or click to view image in full size

Introduction to XMLHttpRequest (XHR)

The XMLHttpRequest (XHR) object allows web pages to interact with servers asynchronously, enabling partial updates to a page without requiring a full refresh. This functionality revolutionized how web applications behave, allowing for a smoother, more dynamic user experience.

Some of the earliest implementations of this technology can be seen in Gmail, where new requests were sent every 20–30 seconds to check for new emails, updating the inbox without requiring a full page refresh.

Origins of XMLHttpRequest

Some of the earliest uses of XHR were seen in services like Gmail, where requests were sent every 20–30 seconds to check for new emails without reloading the entire page. This was revolutionary at the time, as it enabled a dynamic, real-time user experience.

The concept behind the XMLHttpRequest object was first created by the developers of Outlook Web Access for Microsoft Exchange Server 2000. This laid the foundation for the "Ajax" (Asynchronous JavaScript and XML) pattern. The pattern became widely known for enabling asynchronous updates in web applications.

The IXMLHTTPRequest interface was developed and implemented into the second version of the MSXML (Microsoft XML Core Services) library, which was shipped with Internet Explorer 5.0 in March 1999. This allowed access to the interface via ActiveX controls. However, versions of Internet Explorer 5 and 6 didn’t fully support the XMLHttpRequest object, and compatibility had to be ensured through object detection.

In 2006, Microsoft added the XMLHttpRequest object identifier to its scripting languages with the release of Internet Explorer 7. Meanwhile, Mozilla also developed a similar interface called nsIXMLHttpRequest for its Gecko layout engine. This was implemented as a JavaScript object called XMLHttpRequest starting with version 0.6 of Gecko in December 2000, though it was fully functional by version 1.0 in June 2002.

Over time, other browsers such as Safari 1.2 (February 2004), Konqueror, Opera 8.0 (April 2005), and iCab 3.0b352 (September 2005) adopted the XMLHttpRequest object, making it a cross-browser standard.

With the rise of JavaScript libraries like jQuery, developers no longer needed to interact with the raw XMLHttpRequest API directly. These libraries provided convenient wrappers, making it easier to work with XHR functionality.

see more at Wikipedia.

Basic XMLHttpRequest Code Example

Here’s a simple example to make a GET request using XMLHttpRequest:

const request = new XMLHttpRequest();
const url = 'https://jsonplaceholder.typicode.com/todos/1';
request.open("GET", url);
request.send();

To send an HTTP request, follow these steps:

  1. Create an XMLHttpRequest object.
  2. Open a URL using the open() method.
  3. Send the request with the send() method.

After the transaction completes, the object will contain useful information such as the response body and the HTTP status of the result.

But we need to make something with data (response) or catch errors so we will use addEventListener().

addEventListener() is an inbuilt function in JavaScript which takes the event to listen for and a second argument to be called whenever the described event gets fired. Any number of event handlers can be added to a single element without overwriting existing event handlers.

so we will use the load event, this will be fired after receiving the response from the server.

Let’s see this example :

const request = new XMLHttpRequest();
const url = 'https://jsonplaceholder.typicode.com/todos/1';
request.open("GET", url);
request.send();
request.addEventListener('load', (e) => {
if (request.status === 200) {
const response= JSON.parse(request.response);
console.log(response);
/*
console will print the response
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
*/
}
});

XMLHttpRequest Events

Some of the events you can use with XMLHttpRequest include:

  • load
  • start
  • progress
  • abort
  • error
  • loadend
  • readystatechange

Understanding readyState

The readyState property tracks the status of the request. It returns a number between 0 and 4:

  • 0: Request not initialized.
  • 1: Server connection established.
  • 2: Request sent.
  • 3: Request being processed.
  • 4: Request completed, response is ready.

Example: Handling readyState and status

Let’s update the responseHandler function to check the readyState:

function responseHandler() {
if (request.readyState === 4 && request.status === 200) {
const response = JSON.parse(request.response);
console.log(response);
}
}

I’m sure that you are thinking about headers now 😊

you can use setRequestHeader(header, value) to set headers to request:

request.setRequestHeader('Accept-Language', 'en-US');

make sure to put this line after the request.open() if not you will get this error in the console:

Press enter or click to view image in full size

Error Handling

In addition to handling successful requests, it’s important to handle potential errors that might occur. Here’s an example of handling different events:


function errorHandler() {
console.log('Sorry, something went wrong.');
}

function abortHandler() {
console.log('Sorry, the request was aborted.');
}

// fires when an error occurs.
request.addEventListener('error', errorHandler);
// fires when the request is aborted.
request.addEventListener('abort', abortHandler);

Progress Event Handler:

request.addEventListener('progress', updateProgress);

function updateProgress(event) {
if (event.lengthComputable) {
let percent = (event.loaded / event.total) * 100;
console.log(percent);
} else {
console.log('Unable to compute progress information since the total size is unknown.');
}
}

updateProgress() fires when the readyState changes.

The progress event handler, specified by the updateProgress() function in this example, receives the total number of bytes to transfer as well as the number of bytes transferred so far in the event's total and loaded fields. However, if the lengthComputable field is false, the total length is not known and will be zero.

  • event.loaded the amount of data currently transferred.
  • event.total the total amount of data to be transferred.

Example.

(1/4) * 100 = 25%

It's good for user experience and make sure to use some animation =😁

Complete Example with Events

Here’s a complete example that handles the load, error, abort, and progress events:

const request = new XMLHttpRequest();
const url = 'https://jsonplaceholder.typicode.com/todos/1';

request.addEventListener('load', responseHandler);
request.addEventListener('progress', updateProgress);
request.addEventListener('abort', abortHandler);
request.addEventListener('error', errorHandler);

function responseHandler() {
if (request.readyState === 4 && request.status === 200) {
const response = JSON.parse(request.response);
console.log(response);
} else {
console.log('Something went wrong', request.status);
}
}

function updateProgress(event) {
if (event.lengthComputable) {
let percent = (event.loaded / event.total) * 100;
console.log(percent);
}
}

function abortHandler() {
console.log('Sorry, the request was aborted.');
}

function errorHandler() {
console.log('Sorry, something went wrong.');
}

request.open("GET", url);
request.setRequestHeader('Accept-Language', 'en-US');
request.send();

Types of Requests: Asynchronous vs. Synchronous

A request made via XMLHttpRequest can fetch the data in one of two ways, asynchronously or synchronously. The type of request is dictated by the optional async argument (the third argument) that is set on the XMLHttpRequest.open() method. If this argument is true or not specified, the XMLHttpRequest is processed asynchronously, otherwise the process is handled synchronously.

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

Asynchronous requests allow the browser to continue executing other code while waiting for the request to complete, avoiding UI freezes. Synchronous requests block the execution of code, which can result in a poor user experience.

Further reading

That’s it for now! I hope this gives you a solid understanding of the inner workings of XMLHttpRequest. Happy coding! 😊

--

--