I'm working on something that will add a widget to a customer's site, and I want to load my js asynchronously so as not to block the customer's page loading. I've been reading a lot of threads about this, and have been trying to implement the pattern suggested here as my project is very similar:
http://friendlybit.com/js/lazy-loading-asyncronous-javascript
The problem I have is the code in my dynamically-loaded javascript file just doesn't get executed. Sorry if this seems to be a duplicate question, but I've spent hours searching and trying slightly different techniques, and I've read numerous posts including these stackoverflow questions:
but I'm still struggling to make this work, so I was hoping if I ask the question directly someone here might be able to help me out!
I've currently got the following as a really basic test; obviously there's a lot more going on in my real script, but I just need to understand what's happening here (or, in fact, what's not happening).
So in my code file "test.js" I simply have:
run_test = function () {
alert('hello from test');
};
then on the page I have:
(function () {
load_test = function () {
var t = document.getElementsByTagName('script')[0];
var s = document.createElement('script');
s.type = 'text/javscript';
s.async = true;
s.src = 'test.js';
s.onload = s.readystatechange = function () {
if (run_test) run_test();
s.onload = null;
s.onreadystatechange = null;
};
t.parentNode.insertBefore(s, t);
};
load_test();
})();
I've already tried several variations on this - I've tried removing "s.async = true" just to see if it makes a difference, but it doesn't. I originally had the following instead of "load_test();", as suggested in the first post I mentioned:
window.attachEvent ? window.attachEvent('onload', load_test) : window.addEventListener('load', load_test, false);
but the result is always the same, I never see the message "hello from test". In fact I can even put alerts in the load_test function - if I put an alert just before the line "s.onload = s.readystatechange .." I see that message, but an alert within that onload function never appears. So it would appear that the dynamically added script's onload never fires.
BTW as an aside - may or may not be relevant, but I generally test in Firefox, and if I look at the html in firebug, I see the test.js script has been loaded, but if I expand that node I just see the message "Reload the page to get source for ...". Doesn't matter how many times I reload the page, I can't see the code. I have tried testing in other browsers with the same results.
Can't help feeling I'm missing something fundamental here; any help would be very much appreciated!
Pete
Thanks all for the input.
@zzzzBov, thanks for the example, although I'm not sure I completely understand still - I thought that "onload" would fire once after the script finishes loading, in the same way as attaching code to the onload event of the page. My understanding of "onreadystatechange" was that it was just to catch the same thing in IE.
In response to your comments, the new script is inserted in the head of the page (with the insertBefore statement) right before the original script block (assuming the original script block is in the head, which it is).
With regard to the test.js path, I omitted the path just to simplify the example. My path to the script is definitely correct; I can see via firebug that the script is actually added (to the head).
My problem was that after the script loaded, it simply failed to run, but I think I was actually hitting some caching problems as I've since got this working using the pattern described in the first link I posted above (here it is again for good measure: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/).
So my code is something like this:
(function () {
var addscript = function () {
var h = document.getElementsByTagName('head')[0],
s = document.createElement('script');
s.type = "text/javascript";
s.async = true;
s.src = "myscript.js";
h.appendChild(s);
};
window.attachEvent ? window.attachEvent('onload', addscript) :
window.addEventListener('load', addscript, false);
})();
If you check the comments on that post, I think it's explained somewhere why it's a good idea to still include "s.async = true" even though in this case the script is attached to the window onload event.
My "real" main script does actually require jQuery, so I think my eventual solution will be to use something like this to load jQuery, then once I know that's loaded, let jQuery do the work of loading any other scripts I need.
Thanks again for the help.
Pete
You've got a few issues with your script. Here's one that should work.
function loadScript(src, callback)
{
var s, r;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.onload = s.onreadystatechange = function() {
//console.log( this.readyState ); //uncomment this line to see which ready states are called.
if ( !r && (!this.readyState || this.readyState == 'complete') )
{
r = true;
callback();
}
};
document.body.appendChild(s);
}
The issue with your load_test
function is that it'll call run_test()
before the new script has executed. Your script will remove the onload
and onreadystatechange
event callbacks at the first onreadystatechange
event which is typically loading
.
Also, async
should be unnecessary, as the newly added script will be inserted at the end of the document.body
wherever that may be. If you'd like to load the script after the rest of the page, then wait for the rest of the page to load (body.onload
or document.onreadystatechange
) before calling loadScript
.
The biggest issue with your script sounds like test.js
doesn't exist at the path it's being called. Make sure that adding <script type="text/javascript" src="test.js"></script>
inline actually works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With