Available callbacks
The simplest callback is the
onerror
attribute. It can be attached to a script tag like this:
script.onerror = function() {
/* code here is called if the download fails */
}
For completeness, there is also an
onload
attribute. It's analagous to onerrer
except that it indicates success rather than failure. It can be attached to a script tag like this:
script.onload = function() {
/* code here is called if the download succeeded */
}
Finally, IE supports
onreadystatechange
, similarly to the XHR attribute of the same name. The supplied callback will be invoked as the download progresses. The state of the download can be queried via the readyState
attribute, which will reach state 'loaded' and/or 'complete'.
script.onreadystatechange= function () {
if (script.readyState == 'loaded') {
script.onreadystatechange = function () { } // prevent duplicate calls
/* error handling code goes here */
}
}
Results
I used the test page to see which of the three events are fired on several browsers.
Loading a bad page:
Firefox 3.5: onerror
Safari 4: onerror
Chrome 4: onerror
IE 7: onreadystatechange
IE 8: onreadystatechange
Loading a good page:
Firefox 3.5: onload
Safari 4: onload
Chrome 4: onload
IE 7: onreadystatechange (if not cached)
IE 8: onreadystatechange (if not cached)
Analysis
The onerror attribute works on all browsers but IE. For IE, onreadystatechange is available. Conveniently, no browser supports both of them, so a handler hooked up to both of them will fire exactly once.
A complication on IE is that onreadystatechange doesn't differentiate whether the download succeeded or not. Downloading a non-cached version looks the same as a download failure. Thus, any code using onreadystatechange needs to check whether the download succeeded or not.
Followup: Order of evaluation versus onreadystatechange
On IE, if onreadystatechange indicates the installation is complete, in what circumstances should the loading be considered to have failed?
I did a followup test where the loaded code (exists.js) does a window.alert. That way, I can see which happens first: the alert, or the onreadystatechange callback. On both IE7 and IE8, the alert happens first. That means if the script sets a global flag to true once it loads, the onreadystatechange callback can check it and reliably determine whether the download has succeeded.
Test script
<head>
<title>Test page</title>
<script>
function loadFile(url) {
var head = document.getElementsByTagName('head').item(0);
var script = document.createElement('script');
script.src = url;
script.onload = function() {
window.alert("onload called");
}
script.onerror = function() {
window.alert("onerror called");
}
script.onreadystatechange= function () {
if (script.readyState == 'loaded') {
script.onreadystatechange = function () { }
window.alert("onreadystatechange (" + script.readyState + ")");
}
}
head.appendChild(script);
}
function good() {
loadFile("exists.js");
}
function bad() {
loadFile("bad.js");
}
</script>
</head>
<body>
<input type="button" value="good" onclick="good()">
<input type="button" value="bad" onclick="bad()">
</body>
No comments:
Post a Comment