Using AJAX to asynchronously load slow XML files

More and more I’ve come across situations where I want to use AJAX to download a XML file to use in the interface but know beforhand that the file will take a long time to load. With asyncroneous download of XML files by JavaScript, which is kind of what the buzz word AJAX is all about, you must be carefull not to leave the client in limbo between a useable interface and a locked up screen.

Unfortunately this script only works in Internet Explorer, useful tips of how to port it properly (with the asynchronous property intact) would be highly appreciated.

Here is a simple description of the basic functions needed to perfom a asynchronous download where the user will have the option to abort.

First we need a simple function that download the XML, this is pretty standard and the code is lovingly ripped off from w3school.com.

function loadXml(sUrl){
	try{
		//Internet Explorer
		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
	}
	catch(e){
		try{
			//Firefox, Mozilla, Opera, etc.
			xmlDoc = document.implementation.createDocument("","",null);
		}
		catch(e) {
			alert(e.message)
		}
	}
	try{
		xmlDoc.async = 'true';
		xmlDoc.load(sUrl);
	}
	catch(e) {
		alert(e.message)
	}
}

This code is pretty straight forward and I assume you allready know of it, if not read the guide over at W3Schools. The only difference in the above code compared to that from the tutorial over at W3Schools is the flag “xmlDoc.async = ‘true'”. This means that the code will continue executing after the load is called without waiting for the load to finish. This will place the status of the xmlDoc variable in a limbo which can be checked with the “readyState” flag.

To check if our file is ready to use we have a test-loop that will check if readyState changes:

function testReadyLoop(){
	i++;
	if (xmlDoc.readyState == 4){
		// the file has completed the download
		alert('xmlDoc ready to use! Contents:n' + xmlDoc.xml);
		// TODO: add code here of what to do with the file
	}
	else{
		if (!abortXmlLoad){
			// try again in 1 second
			setTimeout("testReadyLoop();",1000);
		}
		else{
			// stop loading the xml file
			xmlDoc.abort();
			alert('Loading of the XML file aborted!');
		}
	}
}

The incrementation of the variable “i” is just a counter that will be used later and the “abortXmlLoad” is a boolean if the loop should continue or not, these will be explained later. What happens in this function is that it first tests if readyState is 4 which indicates that the file is ready to be used, if this is the case we simple show an alert with the contents of the file, here more intelligent code would be placed. If it’s not ready it checks if it should continue waiting for the file or not, if it should it calls itself in 1 second (1000 ms) otherwise it aborts the loading and simply stops.

To abort a download we need to set the “abortXmlLoad” flag to true, a short function is needed for this:

function abortAsyncXML(){
	// set the abort flag to true
	abortXmlLoad = true;
}

Now we have all the functions needed for the asynchronous download, a last function is added to tie them all togheter:

function loadAsyncXML(sUrl){
	// set abort to false and start download
	abortXmlLoad = false;
	i = 0;
	loadXml(sUrl);
	// start loop to check when ready
	testReadyLoop();
}

This function first resets the values of “i” and “abortXmlLoad” and then it calls the download and after that starts the loop to test if the download is ready. The file will now download silently in the background and pop an alert when ready unless someone calls “abortAsyncXml” before that happens.

As you may have noticed there are a few global variables I use across the functions that also need to be added to the top of the script:

var xmlDoc;
var abortXmlLoad;
var i;

To use this script a small form need to be added to the page:

<form>
<input type="button" value="load" onclick="loadAsyncXML('sample.xml');">
<input type="button" value="abort" onclick="abortAsyncXML();">
</form>

This will load the file “sample.xml” and abort if the abort button is pushed. In order to test that the abort button is working you would have to build a slow loading page that simulates long loading time.

I will post a link to the full code and sample later. Hope you found this helpful.

Slow loading with Google Analytics

I experienced my pages slowing down when using Google Analytics togheter with my Firefox AddOn NoScript. Since I’m far from the only one using NoScript I found this not acceptable and worked out a possible work around.

The reason for the slow down is likely the timeout of the connection between my domain (where I’ve allowed scripts to run) and Googles domains (where I might or might not have allowed scripts).

Googles code look like this (where “UA-1111111-1” is your tracking ID):

<script type=”text/javascript”>
var gaJsHost = ((“https:” == document.location.protocol) ? “https://ssl.” : “http://www.”);
document.write(unescape(“%3Cscript src='” + gaJsHost + “google-analytics.com/ga.js’ type=’text/javascript’%3E%3C/script%3E”));
</script>
<script type=”text/javascript”>
var pageTracker = _gat._getTracker(“UA-1111111-1”);
pageTracker._initData();
pageTracker._trackPageview();
</script>

The first part of the code creates an obfuscated loading of the script located at google-analytics.com/ga.js. It picks a prefix of www if it’s a standard connection and ssl if it’s  an encrypted connection. The problem is that NoScript does not recognize this code and ends up in a deadlock of wether or not to allow the script to be run. My guess is that there is another script loaded from another domain called googlesyndication.com which fails to enter the NoScript-test and locks the loading of the page.

A possible fix that I’m still evaluating but which should do the trick is the following (code in bold added):

<script src=”http://www.google-analytics.com/ga.js” type=”text/javascript”></script>
<script type=”text/javascript”>
var pageTracker = _gat._getTracker(“UA-1111111-1”);
pageTracker._initData();
pageTracker._trackPageview();
</script>

As you can see I’ve made the obfoscated code clear text code and chosen the http://www-prefix (since I’m not using an encrypted connection for my server). Should you use encryption on your site simply switch http://www to https://ssl instead (this is what the javascript used to do). If you have a page which might be loaded encrypted or normally then you would have to include this choice earlier in a server side script for example.

After this fix Google Analytics works like a charm togheter with NoScript on any script-level setting for me.

Try this at your own risc, this is still experimental to me as well!