Take the 2-minute tour ×

The W3C spec suggest following implementation: Some simple code to do something with data from an XML document fetched over the network:

function processData(data) {
  // taking care of data

function handler() {
  if(this.readyState == this.DONE) {
    if(this.status == 200 &&
       this.responseXML != null &&
       this.responseXML.getElementById('test').textContent) {
      // success!
    // something went wrong

var client = new XMLHttpRequest();
client.onreadystatechange = handler;
client.open("GET", "unicorn.xml");

Is this implementation really correct?

During debug I found cases when the readystatechanged event handler is called more than once in a row with the same value of readyState == 4. I guess this behavior is correct, as specs says that each change of state must fire the event, and that readyState must always be equal to current state, so if several events pile up in the events queue, it's quite obvious, that one will get multiple calls with readyState == 4.

http://jsfiddle.net/44b3P/ -- this is the above example augmented with debugger call to pause execution just after the request is send, and with alert() in the processData. Once you unpause the execution you will get 3 alerts.

This example from w3c seems to be copy&pasted in multiple places in the web -- in particular OpenSocial seems to handle xhr events this way. Is it correct?

share|improve this question

2 Answers 2

up vote 5 down vote accepted

I also saw the same behavior (DONE 200 being hit more than once, i.e. 2...n times) when debugging in Chrome Developer Tools.

To make it work always in debug mode as well, I found two options:

  1. Use onload to verify the success of an XMLHTMLRequest W3C Spec

    client.onload = handler;

    This version will not work in IE8. It must be a browser that implements the XMLHttpRequestEventTarget interface

  2. Remove the onreadystatechange handler as soon as you have a DONE 200 state.

    client.onreadystatechange = function() {
        // check if request is complete
        if (this.readyState == this.DONE) {
            if (this.onreadystatechange) {
                client.onreadystatechange = null;

I have also opened an issue in Chromium for this problem, providing your Fiddle (Thanks!)

share|improve this answer
Just as an addendum - using the originally provided code, this.onreadystatechange = null; is sufficient, you don't need the original reference to the XHR (client). –  Monchoman45 Feb 15 '13 at 19:38
It didn't work when I tried using delete xhr.onreadystatechange, changing it to xhr.onreadystatechange = null worked well. –  Noam Gal Feb 20 '13 at 8:48
I have edited the code to use = null instead of delete –  Gabriel Petrovay Feb 24 '13 at 9:51
to me this solution dint work, but the second answer in this solution worked stackoverflow.com/questions/5728509/… –  web_dev Oct 21 at 20:40

I have never had my onreadystatechange handler executed multiple times with a readyState of 4.

I think assuming a single execution on DONE is correct.

share|improve this answer
well, I have. That's quite easy to reproduce: jsfiddle.net/44b3P –  qbolec Oct 7 '12 at 9:08
Only one alert appears every time I reload the page, sorry. (latest Chrome) –  Jan Kuča Oct 7 '12 at 12:09
The problem is ONLY in debug mode (I tested it only on Mac). You must open the Developer Tools and then reload the page. It is also not "deterministic" (for the user), since it sometimes (rarely) doesn't happen. I also could not understand the logic about how many times it is called. –  Gabriel Petrovay Nov 27 '12 at 13:23

Your Answer


