AJAX Events

Chapter 8 10 mins

Learning outcomes:

  1. Different events for XMLHttpRequest()
  2. onreadystatechange, onloadstart, onload..
  3. Request abortion and timeout

Introduction

At this point in this course we are well versed with many important concepts ideas and key ideas that include the mechanism of AJAX together with the XMLHttpRequest() object, how states and status work together to ensure successful fetches and how to handle responses, in the most suitable way.

We even saw an event - onreadystatechange - to track the state of the request and determine when does it go to completion.

Event are really helpful! They are utilised extensively in numerous applications around the web, be they simple or complex. Without events we couldn't even imagine the dynamic and interactive layer JavaScript adds to web applications.

AJAX follows along in this run - it has got some extremely useful events at the dispense which developers shall understand how to work with and be able to incorporate them into their projects to make the most out of them. In this chapter we'll go one-by-one over all of the events currently supported by AJAX, and see how and where to use to each event.

The state monitor

As it's now one of our close friends, it shouldn't hurt to start off this chapter by considering the onreadystatechange event once more.

The state monitor event, onreadystatechange, fires each time the readyState of an AJAX request changes. Usually we are concerned with state 4 as this is the time when the request reaches completion.

Following is a simple example, logging the readyState each time the event onreadystatechange fires:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function() {
    console.log(this.readyState);
}

xhr.open("GET", "foods.html", true);
xhr.send();

You already know the output to this code back from the AJAX States chapter. The console will show the numbers 1 to 4 in increasing order denoting the different states of the request.

1
2
3
4

Now at this moment, there is one fact worth discussing about the onreadystatechange event.

When XMLHttpRequest() was standardised, the onreadystatechange event was the only way to listen for request completion. However as time went on and things developed, newer events sprung up to mimic the functionality of onreadystatechange as used with different conditionals to check for different states.

Next we explore two such events: onloadstart and onload.

Loading started

The event onloadstart fires when the headers of the response have been successfully received. This implies the start of the process loading the actual content.

In the code below we listen to the event onloadstart and log the string "Headers received!" and the current state of the request, once it is dispatched:

var xhr = new XMLHttpRequest();

xhr.onloadstart = function() {
    console.log("Headers received!");
    console.log("readyState:", this.readyState);
}

xhr.open("GET", "foods.html", true);
xhr.send();
Headers received!
readyState: 2

As you can see and recall, this event mimics onreadystatechange with a check for readyState == 2, as shown below:

// same as onloadstart
xhr.onreadystatechange = function() {
    if (this.readyState == 2) {
        console.log("Headers received!");
        console.log("readyState:", this.readyState);
    }
}
If your application has to support older browsers then you have to use onreadystatechange as shown above, instead of onloadstart.

Request complete

The name onload is so common that it couldn't keep itself from creeping into the XMLHttpRequest() object.

The onload event fires when the underlying request reaches completion.

As you know, processing the content of a requested file can only be done once it is fetched completely (and successfully). Likewise it makes sense to put any response handling operations of your AJAX code inside the onload event, or equally inside onreadystatechange as we'll see below.

Consider the following example where we log the string "Request finished!" and the current state of the request, once onload is dispatched:

var xhr = new XMLHttpRequest();

xhr.onload = function() {
    console.log("Request finished!");
    console.log("readyState:", this.readyState);
}

xhr.open("GET", "foods.html", true);
xhr.send();
Request finished!
readyState: 4

Just like onloadstart mimics onreadystatechange with a check for state 2, onload mimics it with a check for state 4:

// same as onload
xhr.onreadystatechange = function() {
    if (this.readyState == 4) {
        console.log("Headers received!");
        console.log("readyState:", this.readyState);
    }
}

Looking for errors!

Can you guess the name of the event which deals with errors happening with an AJAX request? Think on it - it's very common!

The onerror event does the most boring job of all events i.e monitors errors.

However, it is important to realise exactly which errors does onerror react to; since otherwise there exists many errors that could possibly happen in an AJAX request of which only some show up in onerror.

Specifically, any network-related error occuring in an AJAX request causes the onerror event to be dispatched. For example the user may be offline, requesting for a file cross-origin, or have the DNS server disabled - all these are instances of network errors and hence will show up in onerror.

Consider the following example that makes an alert once an error occurs in the AJAX request:

var xhr = new XMLHttpRequest();

xhr.onerror = function() {
    alert("An error occured.")
}

xhr.open("GET", "foods.html", true);
xhr.send();

Open the link below in your browser, disable your internet connection and then press the button to dispatch a request. Since an active connection is required to send a request to a destination server, doing so will raise an error and likewise bring onerror into action.

Live Example

Often times, devlopers assume that if the response comes with a 404 Not Found status, onerror will take care of this problem too. Unfortunately this doesn't happen!

It is extremely important to realise the fact that onerror only takes into account network errors. To throw errors on 404, and other, responses, we have to manually code the logic to first check status and operate likewise.

Cancelling the request

Imagine pressing a download button to pull in a file from a server using AJAX, and then realising that it's the wrong file and finally pressing the cancel button.

This scenario utilises what is commonly known as 'aborting a request'. To abort a request simply means to cancel it.

As soon as an AJAX request is aborted, the connection between the client and the server is put off, the ongoing request terminated and the onabort event fired. In the example above, the cancel button was thus serving the purpose of aborting the ongoing AJAX request.

This idea of request abortion is very basic but unclear uptil now - we still don't know how to actually abort an AJAX request. Well it's extremely simple - just use the abort() method.

If abort() is called while an AJAX request is under its way to completion, the request is brought to a halt and ultimately the onabort event is fired. Each time this method is called, onabort is dispatched by the browser.

The significance of abort() is that it can be put in click event handlers to provide cancelling functionalities to AJAX applications - a feature surely worth the effort if in your AJAX inventory!

Following is a simple illustration where we call abort() at the click of a button, saved in the variable cancelButton, and make an alert inside the handler for onabort:

var xhr = new XMLHttpRequest();

// click handler for the cancel button
function abortRequest() {
    xhr.abort(); // abort the request
}

xhr.onabort = function() {
    alert("Request aborted!");
}

xhr.open("GET", "foods.html", true);
xhr.send();
In the link below, the file we request for has a manual delay of 3 seconds given so that you can easily understand the working of abort() and onabort.

Live Example

Time's up

There are many occasions when requests can take more than just long to come back with a response. Ideally, in these cases we don't want to just sit out there and wait for ever until the first byte of the response is received.

The concept of timeouts was thus born to tackle with such cases!

The timeout property specifies the time, in milliseconds, after which a request will automatically be terminated by the browser. By default, this property has no value which means that there aren't any time limits.

Once the timeout for an AJAX request is reached the ontimeout event is fired. Developers can work with this mechanism to handle AJAX requests that cross certain time limits - limits of patience!

In the example below we fetch a file that takes too long to return a response (somewhere around 3 seconds), set the timeout to 2 seconds and listen to the ontimeout event. Once a timeout occurs (which will in this case) we make an alert.

var xhr = new XMLHttpRequest();

xhr.timeout = 2000; // timeout of 2000 milliseconds

// execute after timeout occurs
xhr.ontimeout = function() {
    alert("Time's up!");
}

xhr.open("GET", "foods.html", true);
xhr.send();

Live Example

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage