通过$ .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的好信息。