Prevent double callback execution in IE9
After you read this article, please read the thread in the comments that starts with a response from Steve Souders. As it turns out, my client was using the code from Steve's EFWS book, first edition, published June 2009. That makes the code examples in the book almost 2 years old. Steve has updated his online Script Onload example page and that updated code does not result in the double execution in IE9.
I will update this article accordingly as soon as possible.
One of my clients sent me an email the other day about weird behaviour on his site: the Flash animation on the homepage looked weird in IE9. He was using Steve Souders' Script Onload technique for loading the SWFobject lib in a non-blocking way, and then executing some inline JavaScript as soon as SWFobject finished loading (the callback). Steve recommends this technique in his book Even Faster Web Sites and it always worked just fine in all browsers. But now there is IE9 and it fails. What is going on?
In short: IE9 supports both the load event and the readystatechange event.
With the way Steve's Script Onload code is constructed, this results in double execution of the callback function in IE9.
Luckily, there is an easy solution. Read on ...
Original code
For those who are unfamiliar with Steve's Script Onload code, here it is:
<script>
function callback() {
// this is the callback function
// executes after external script finishes loading
}
var script = document.createElement('script');
script.src = "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js";
script.onloadDone = false;
script.onload = function() {
script.onloadDone = true;
callback();
};
script.onreadystatechange = function() {
if (("loaded" === script.readyState || "complete" === script.readyState) && !script.onloadDone) {
script.onloadDone = true;
callback();
}}
document.getElementsByTagName('head')[0].appendChild(script);
</script>
You can see there are two event handlers. IE9 acts on both handlers and this results in the double execution. In this test case, the JPG image is loaded twice.This waterfall chart (test page 1) clearly shows the double execution in IE9:

View full test results on Webpagetest.org
Optimized code
The solution is simple, effective and future proof and you can read all about it in Nicholas Zakas' article Loading JavaScript without blocking. In summary:
- use an if-else statement to prevent a browser from handling both events.
- in the if-else statement, check for support in the browser for the
readyStateproperty first (all IE browsers support this) - if the browser does not support
readyState, listen for theloadevent
<script>
function callback() {
// this is the callback function
// execute after external script finishes loading
}
var script = document.createElement('script');
script.src = "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js";
if (script.readyState) { // IE, incl. IE9
script.onreadystatechange = function() {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else {
script.onload = function() { // Other browsers
callback();
};
}
document.getElementsByTagName('head')[0].appendChild(script);
</script>
Does this solve the problem? Yes, it does (test page 2):
View full test results on Webpagetest.org
Your feedback please!
I'm looking forward to receiving your questions and remarks.
Leave your comment below (now comment), send me a message via Twitter or via email: aaron {at} aaronpeters {dot} nl.
Like it? Share it!