通过$ .getScript完成所有脚本加载后调用处理程序

所以我们假设我们通过$.getScript加载一堆脚本:

 $.getScript( 'js/script1.js' ); $.getScript( 'js/script2.js' ); $.getScript( 'js/script3.js' ); 

现在,我想在所有这些脚本完成加载时调用一个处理程序。 我尝试绑定全局ajaxStop事件的处理程序。 根据文档 ,如果不再处理Ajax请求,则会触发ajaxStop全局事件。

 $( document ).ajaxStop( handler ); 

但它不起作用(不调用处理程序)。

现场演示: http //jsfiddle.net/etGPc/2/

我怎样才能做到这一点?

你反正做错了:)

这是可能发生的事情之一:想象一下脚本是否被缓存,然后它们可能会立即被加载。 所以,直接在第一次调用$.getScript( 'js/script1.js' ); 脚本将可用并且$ .ajaxStop(可能!!!)被调用,在最坏的情况下会发生三次。

为了间接回答你的问题,我会提出一个完全避免这种竞争条件的不同解决方案。 你可以在这里试试: 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 + "
" ); // all loaded now? if( loaded.length == urls.length ){ log.append( "all done!" ); } } ); } );

如果您之前没有见过jQuery.map :它与for循环没有什么不同:)

这里的另一个优点是,如果您同时进行其他ajax请求,则此方法不会混淆。

ps为了避免命名冲突,你可以将整个事物包装在一个自动执行的函数中,即

 function(){ var urls, log, loaded; ... all code here ... } (); 

更新:重新编写代码…

 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 + '
' ); if( loadedUrls.length === urls.length ){ $( log ).append( 'all done!' ); } }); });

现场演示: http //jsfiddle.net/etGPc/10/

我在这个问题上多挖了一点,这确实是跨域脚本请求,这是一个警告。 正如我在评论中发布的那样,该场景已经实现,因此它将global选项设置为false 。 这使得jQuery不会触发全局ajax事件。 (不知道为什么会这样实现。)

这可以通过这个小提琴来确认(传递意味着ajaxStop被触发):

  • 跨域,没有脚本:通过
  • 跨域,脚本: 失败
  • 没有跨域,没有脚本:通过
  • 没有跨域,脚本:通过

最直接的做法是简单地添加另一个prefilter,强制global选项为true:

 jQuery.ajaxPrefilter( "script", function() { s.global = true; }); 

这也使得这种失败的场景在小提琴中传递。

在处理我自己的问题时,我发现了一个更好,更优雅的解决方案,它正在使用jQuery deffered对象 。 我想你已经知道了这个函数,可能是另一个用例,但它非常适合加载文件,并在完成eveything时触发函数。 代码如下:

 function getLatestNews() { return $.get('/echo/js/?delay=2&js=', function(data) { console.log('news data received'); $('.news').css({'color':'blue'}); }); } function getLatestReactions() { return $.get('/echo/js/?delay=5&js=', function(data) { console.log('reactions data received'); $('.reactions').css({'color':'green'}); }); } function prepareInterface() { return $.Deferred(function(dfd) { var latest = $('.news, .reactions'); latest.slideDown(500, dfd.resolve); latest.addClass('active'); }).promise(); } $.when( getLatestNews(), getLatestReactions(), prepareInterface() ).then(function() { console.log('fire after requests succeed'); $('.finished').html('I am done!'); }).fail(function() { console.log('something went wrong!'); }); 

我做了一个小小提琴,你可以看看代码。

http://jsfiddle.net/saifbechan/BKTwT/

你可以在那里查看正在运行的副本,我从本教程中获取了片段,值得阅读整个教程,很多关于异步ajax的好信息。

http://msdn.microsoft.com/en-us/scriptjunkie/gg723713