views:

219

answers:

2

This code only works when async is set to false, why?

var contact =
{
 XMLHttp : null,
 XMLDoc : null,
 TXTDoc : null,

 getData : function(dataSource)
 {
  contact.XMLHttp = new XMLHttpRequest();
  contact.XMLHttp.open("GET", dataSource, false);
  contact.XMLHttp.onreadystatechange = contact.storeData;
  contact.XMLHttp.send(null);
 },

 storeData : function()
 {
  if(contact.XMLHttp.readyState == 4 && contact.XMLHttp.status == 200)
  {
   contact.XMLDoc = contact.XMLHttp.responseXML;
   contact.TXTDoc = contact.XMLHttp.responseText;
  }
 },

 displayData : function(elementID)
 {
  if(contact.TXTDoc != null)
   document.getElementById(elementID).innerHTML = contact.TXTDoc;
  else{
  document.getElementById(elementID).innerHTML = "can't do it";
  }
 }
}
  • I import it into a html document like so:

    <head>
        <script type="text/javascript" src="contact.js"></script>
    </head>
    
  • And use it like so:

    <body id="para">
    
    
    <script type="text/javascript">
        contact.getData("http://localhost/~olatunjigbadamosi/Books/contact.txt");
        contact.storeData();
        contact.displayData("para");
    </script>
    

+3  A: 

Because it's asynchronous, it takes time to make the HTTP Request to the text file, therefore the callback contact.storeData is called AFTER contact.displayData.

The solution is to simply invoke it inside of storeData, so it fires after it makes the HTTP request to the text file and populates the txtDoc property.

storeData : function()
{
        if(contact.XMLHttp.readyState == 4 && contact.XMLHttp.status == 200)
        {
                contact.XMLDoc = contact.XMLHttp.responseXML;
                contact.TXTDoc = contact.XMLHttp.responseText;
  contact.displayData("para"); 
        }
},

Full code that works for me:

<p id="para"></p>
<button id="foo">go</button>
<script>
var contact =
{
        XMLHttp : null,
        XMLDoc : null,
        TXTDoc : null,

        getData : function(dataSource)
        {
                contact.XMLHttp = new XMLHttpRequest();
                contact.XMLHttp.open("GET", dataSource, true);
                contact.XMLHttp.onreadystatechange = contact.storeData;
                contact.XMLHttp.send(null);
        },

        storeData : function()
        {
                if(contact.XMLHttp.readyState == 4 && contact.XMLHttp.status == 200)
                {
                        contact.XMLDoc = contact.XMLHttp.responseXML;
                        contact.TXTDoc = contact.XMLHttp.responseText;
              contact.displayData("para"); 
                }
        },

        displayData : function(elementID)
        {
                if(contact.TXTDoc != null)
                        document.getElementById(elementID).innerHTML = contact.TXTDoc;
                else{
                document.getElementById(elementID).innerHTML = "can't do it";
                }
        }
},
button = document.getElementById('foo');
button.onclick = function() {
    contact.getData("http://localhost/file.txt");
    contact.storeData();
};

</script>
meder
What do I do if I only want to assign the responses from `XMLHttp` to `XMLDoc and TXTDoc` in the callback function instead of displaying them? My approach which is to insert the statements of `storeData` into an anonymous function attached to `onreadystatechange` doesn't seem to be working.
Tunji Gbadamosi
`contact.XMLHttp.onreadystatechange = contact.storeData`Define another method that invokes both storeData and displayData, `contact.ajaxCallback` or something.
meder
+1  A: 

When you do this synchronously:

contact.getData("http://localhost/~olatunjigbadamosi/Books/contact.txt");
contact.storeData();
contact.displayData("para");

getData is called, the request is sent and returns, getData returns after it finishes and then storeData and displayData run. When you do it async, getData starts the request and returns immediately. Then storeData and displayData are called before they are ready, so they don't work. The results of the request haven't returned yet.

Like meder says, to fix it, you need to do your display in the callback function. That ensures the results from the request are available when displayData is run.

BaroqueBobcat
what if I construct an if statement in my html file that checks that getData is ready before calling storeData and displayData? How would I do that?
Tunji Gbadamosi
You could add a while loop that checks for completion and sleeps, but doing so would prevent anything after your script from loading until it was finished. It is better to stick with the event driven/callback using model. You could have the callback alter the html when it is called.
BaroqueBobcat