So let's say we load a bunch of scripts via $.getScript:
$.getScript( 'js/script1.js' );
$.getScript( 'js/script2.js' );
$.getScript( 'js/script3.js' );
Now, I'd like to invoke a handler when all those scripts finished loading. I tried binding a handler for the global ajaxStop event. According to the docs, the ajaxStop global event is triggered if there are no more Ajax requests being processed.
$( document ).ajaxStop( handler );
but it doesn't work (the handler is not invoked).
Live demo: http://jsfiddle.net/etGPc/2/
How can I achieve this?
I digged a little more into this issue and it's indeed the cross-domain script request that's the caveat. As I posted in the comments, that scenario has been implemented such that it sets the global option to false. This makes jQuery not to fire global ajax events. (No idea why that has been implemented though.)
This can be confirmed with this fiddle (pass means ajaxStop is fired):
The most straight-forward thing to do is simply adding another prefilter which forces the global option to true:
jQuery.ajaxPrefilter( "script", function() {
s.global = true;
});
This also makes this failing scenario pass in the fiddle.
you're doing it wrong anyways :)
here is one of the things that can happen:
imagine the scripts are cached, then they might be loaded in no time.
so, straight after the first call $.getScript( 'js/script1.js' ); the script will be available and $.ajaxStop (might!!!) get called, in the worst case that would happen three times.
to answer your question indirectly i would propose a different solution which avoids this race condition alltogether. you can try it here: http://jsfiddle.net/etGPc/8/
var urls, log, loaded;
// urls to load
urls = [
'https://raw.github.com/h5bp/html5-boilerplate/master/js/script.js',
'https://raw.github.com/h5bp/html5-boilerplate/master/js/plugins.js',
'https://raw.github.com/h5bp/html5-boilerplate/master/js/libs/modernizr-2.0.6.min.js'
];
// urls loaded
loaded = [];
log = $( '#log' );
$.map( urls, function( url ){
$.getScript( url, function(){
// append to loaded urls
loaded.push( url );
log.append( "loaded " + url + "<br>" );
// all loaded now?
if( loaded.length == urls.length ){
log.append( "<b>all done!</b>" );
}
} );
} );
if you haven't seen jQuery.map before: it's not really different from a for-loop :)
another advantage here is that this method doesn't get confused if you have other ajax requests going on at the same time.
p.s. to avoid naming-clashes you can wrap the entire thing in a self-executing function, i.e.
function(){
var urls, log, loaded;
... all code here ...
} ();
Update: Refactored the code a bit...
var urls, loadedUrls, log;
urls = [
'https://raw.github.com/h5bp/html5-boilerplate/master/js/script.js',
'https://raw.github.com/h5bp/html5-boilerplate/master/js/plugins.js',
'https://raw.github.com/h5bp/html5-boilerplate/master/js/libs/modernizr-2.0.6.min.js'
];
loadedUrls = [];
log = $( '#log' )[0];
urls.forEach(function ( url ) {
$.getScript( url, function () {
loadedUrls.push( url );
$( log ).append( 'loaded ' + url + '<br>' );
if( loadedUrls.length === urls.length ){
$( log ).append( '<b>all done!</b>' );
}
});
});
Live demo: http://jsfiddle.net/etGPc/10/
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