So let's say we load a bunch of scripts via $.getScript
:
所以我们假设我们通过$ .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.
现在,我想在所有这些脚本完成加载时调用一个处理程序。我尝试绑定全局ajaxStop事件的处理程序。根据文档,如果不再处理Ajax请求,则会触发ajaxStop全局事件。
$( document ).ajaxStop( handler );
but it doesn't work (the handler is not invoked).
但它不起作用(不调用处理程序)。
Live demo: http://jsfiddle.net/etGPc/2/
现场演示:http://jsfiddle.net/etGPc/2/
How can I achieve this?
我怎样才能做到这一点?
3 个解决方案
#1
2
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.
这是可能发生的事情之一:想象一下脚本是否被缓存,然后它们可能会立即被加载。所以,直接在第一次调用$ .getScript('js / script1.js')之后;脚本将可用并且$ .ajaxStop(可能!!!)被调用,在最坏的情况下会发生三次。
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/
为了间接回答你的问题,我会提出一个完全避免这种竞争条件的不同解决方案。你可以在这里试试: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 :)
如果您之前没有见过jQuery.map:它与for循环没有什么不同:)
another advantage here is that this method doesn't get confused if you have other ajax requests going on at the same time.
这里的另一个优点是,如果您同时进行其他ajax请求,则此方法不会混淆。
p.s. to avoid naming-*es 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/
现场演示:http://jsfiddle.net/etGPc/10/
#2
3
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.)
我在这个问题上多挖了一点,这确实是跨域脚本请求,这是一个警告。正如我在评论中发布的那样,该场景已经实现,因此它将全局选项设置为false。这使得jQuery不会触发全局ajax事件。 (不知道为什么会这样实现。)
This can be confirmed with this fiddle (pass means ajaxStop
is fired):
这可以通过这个小提琴来确认(传递意味着ajaxStop被触发):
- cross-domain, no script: pass
- cross domain, script: fail
- no cross-domain, no script: pass
- no cross-domain, script: pass
跨域,没有脚本:通过
跨域,脚本:失败
没有跨域,没有脚本:通过
没有跨域,脚本:通过
The most straight-forward thing to do is simply adding another prefilter which forces the global
option to true:
最直接的做法是简单地添加另一个prefilter,强制全局选项为true:
jQuery.ajaxPrefilter( "script", function() {
s.global = true;
});
This also makes this failing scenario pass in the fiddle.
这也使得这种失败的场景在小提琴中传递。
#3
2
While dealing with my own problem I found a much better and elegant solution to this problem, and it is using the jQuery deffered object. I think you already know about the function, maybe for another usecase, but it works great for loading files, and fire functions when eveything is done. Code is as follows:
在处理我自己的问题时,我发现了一个更好,更优雅的解决方案,它正在使用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!');
});
I made a small fiddle where you can check out the code.
我做了一个小小提琴,你可以看看代码。
http://jsfiddle.net/saifbechan/BKTwT/
You can check out a running copy there, I took the snippet from this tutorial, it's worth reading the whole tutorial, lot's of good information on asynchronous ajax.
你可以在那里查看正在运行的副本,我从本教程中获取了片段,值得阅读整个教程,很多关于异步ajax的好信息。
#1
2
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.
这是可能发生的事情之一:想象一下脚本是否被缓存,然后它们可能会立即被加载。所以,直接在第一次调用$ .getScript('js / script1.js')之后;脚本将可用并且$ .ajaxStop(可能!!!)被调用,在最坏的情况下会发生三次。
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/
为了间接回答你的问题,我会提出一个完全避免这种竞争条件的不同解决方案。你可以在这里试试: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 :)
如果您之前没有见过jQuery.map:它与for循环没有什么不同:)
another advantage here is that this method doesn't get confused if you have other ajax requests going on at the same time.
这里的另一个优点是,如果您同时进行其他ajax请求,则此方法不会混淆。
p.s. to avoid naming-*es 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/
现场演示:http://jsfiddle.net/etGPc/10/
#2
3
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.)
我在这个问题上多挖了一点,这确实是跨域脚本请求,这是一个警告。正如我在评论中发布的那样,该场景已经实现,因此它将全局选项设置为false。这使得jQuery不会触发全局ajax事件。 (不知道为什么会这样实现。)
This can be confirmed with this fiddle (pass means ajaxStop
is fired):
这可以通过这个小提琴来确认(传递意味着ajaxStop被触发):
- cross-domain, no script: pass
- cross domain, script: fail
- no cross-domain, no script: pass
- no cross-domain, script: pass
跨域,没有脚本:通过
跨域,脚本:失败
没有跨域,没有脚本:通过
没有跨域,脚本:通过
The most straight-forward thing to do is simply adding another prefilter which forces the global
option to true:
最直接的做法是简单地添加另一个prefilter,强制全局选项为true:
jQuery.ajaxPrefilter( "script", function() {
s.global = true;
});
This also makes this failing scenario pass in the fiddle.
这也使得这种失败的场景在小提琴中传递。
#3
2
While dealing with my own problem I found a much better and elegant solution to this problem, and it is using the jQuery deffered object. I think you already know about the function, maybe for another usecase, but it works great for loading files, and fire functions when eveything is done. Code is as follows:
在处理我自己的问题时,我发现了一个更好,更优雅的解决方案,它正在使用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!');
});
I made a small fiddle where you can check out the code.
我做了一个小小提琴,你可以看看代码。
http://jsfiddle.net/saifbechan/BKTwT/
You can check out a running copy there, I took the snippet from this tutorial, it's worth reading the whole tutorial, lot's of good information on asynchronous ajax.
你可以在那里查看正在运行的副本,我从本教程中获取了片段,值得阅读整个教程,很多关于异步ajax的好信息。