jQuery 多个ajax调用的jQuery回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4368946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jQuery callback for multiple ajax calls
提问by MisterIsaak
I want to make three ajax calls in a click event. Each ajax call does a distinct operation and returns back data that is needed for a final callback. The calls themselves are not dependent on one another, they can all go at the same time, however I would like to have a final callback when all three are complete.
我想在一个点击事件中进行三个 ajax 调用。每个 ajax 调用执行不同的操作并返回最终回调所需的数据。调用本身并不相互依赖,它们可以同时进行,但是我希望在所有三个都完成后进行最后的回调。
$('#button').click(function() {
fun1();
fun2();
fun3();
//now do something else when the requests have done their 'success' callbacks.
});
var fun1= (function() {
$.ajax({/*code*/});
});
var fun2 = (function() {
$.ajax({/*code*/});
});
var fun3 = (function() {
$.ajax({/*code*/});
});
采纳答案by subhaze
Here is a callback object I wrote where you can either set a single callback to fire once all complete or let each have their own callback and fire them all once all complete:
这是我编写的一个回调对象,您可以在其中设置单个回调以在全部完成后触发,或者让每个回调都有自己的回调并在全部完成后全部触发:
NOTICE
注意
Since jQuery 1.5+ you can use the deferred method as described in another answer:
从 jQuery 1.5+ 开始,您可以使用另一个答案中所述的延迟方法:
$.when($.ajax(), [...]).then(function(results){},[...]);
for jQuery < 1.5 the following will work or if you need to have your ajax calls fired at unknown times as shown here with two buttons: fired after both buttons are clicked
对于 jQuery < 1.5,以下将起作用,或者如果您需要在未知时间触发 ajax 调用,如下所示,带有两个按钮:单击两个按钮后触发
[usage]
[用法]
for singlecallback once complete: Working Example
对于单一的回调完成后:工作实例
// initialize here
var requestCallback = new MyRequestsCompleted({
numRequest: 3,
singleCallback: function(){
alert( "I'm the callback");
}
});
//usage in request
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.requestComplete(true);
}
});
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.requestComplete(true);
}
});
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.requestComplete(true);
}
});
each having their owncallback when all complete: Working Example
当全部完成时,每个都有自己的回调:工作示例
//initialize
var requestCallback = new MyRequestsCompleted({
numRequest: 3
});
//usage in request
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.addCallbackToQueue(true, function() {
alert('Im the first callback');
});
}
});
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.addCallbackToQueue(true, function() {
alert('Im the second callback');
});
}
});
$.ajax({
url: '/echo/html/',
success: function(data) {
requestCallback.addCallbackToQueue(true, function() {
alert('Im the third callback');
});
}
});
[The Code]
[编码]
var MyRequestsCompleted = (function() {
var numRequestToComplete, requestsCompleted, callBacks, singleCallBack;
return function(options) {
if (!options) options = {};
numRequestToComplete = options.numRequest || 0;
requestsCompleted = options.requestsCompleted || 0;
callBacks = [];
var fireCallbacks = function() {
alert("we're all complete");
for (var i = 0; i < callBacks.length; i++) callBacks[i]();
};
if (options.singleCallback) callBacks.push(options.singleCallback);
this.addCallbackToQueue = function(isComplete, callback) {
if (isComplete) requestsCompleted++;
if (callback) callBacks.push(callback);
if (requestsCompleted == numRequestToComplete) fireCallbacks();
};
this.requestComplete = function(isComplete) {
if (isComplete) requestsCompleted++;
if (requestsCompleted == numRequestToComplete) fireCallbacks();
};
this.setCallback = function(callback) {
callBacks.push(callBack);
};
};
})();
回答by Greg
Looks like you've got some answers to this, however I think there is something worth mentioning here that will greatly simplify your code. jQuery introduced the $.when
in v1.5. It looks like:
看起来您已经对此有了一些答案,但是我认为这里有一些值得一提的地方可以极大地简化您的代码。jQuery$.when
在 v1.5 中引入了。看起来像:
$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
//this callback will be fired once all ajax calls have finished.
});
Didn't see it mentioned here, hope it helps.
没有看到这里提到它,希望它有帮助。
回答by Matt
Not seeing the need for any object malarky myself. Simple have a variable which is an integer. When you start a request, increment the number. When one completes, decrement it. When it's zero, there are no requests in progress, so you're done.
我自己看不到任何对象的需要。简单有一个变量,它是一个整数。当您开始请求时,增加数字。当一个完成时,递减它。当它为零时,没有正在进行的请求,所以你已经完成了。
$('#button').click(function() {
var inProgress = 0;
function handleBefore() {
inProgress++;
};
function handleComplete() {
if (!--inProgress) {
// do what's in here when all requests have completed.
}
};
$.ajax({
beforeSend: handleBefore,
complete: function () {
// whatever
handleComplete();
// whatever
}
});
$.ajax({
beforeSend: handleBefore,
complete: function () {
// whatever
handleComplete();
// whatever
}
});
$.ajax({
beforeSend: handleBefore,
complete: function () {
// whatever
handleComplete();
// whatever
}
});
});
回答by Cory Danielson
It's worth noting that since $.when
expects all of the ajax requests as sequential arguments (not an array) you'll commonly see $.when
used with .apply()
like so:
值得注意的是,由于$.when
期望所有 ajax 请求作为顺序参数(不是数组),您通常会看到这样$.when
使用.apply()
:
// Save all requests in an array of jqXHR objects
var requests = arrayOfThings.map(function(thing) {
return $.ajax({
method: 'GET',
url: 'thing/' + thing.id
});
});
$.when.apply(this, requests).then(function(resp1, resp2/*, ... */) {
// Each argument is an array with the following structure: [ data, statusText, jqXHR ]
var responseArgsArray = Array.prototype.slice.call(this, arguments);
});
This is because $.when
accepts args like this
这是因为$.when
接受这样的参数
$.when(ajaxRequest1, ajaxRequest2, ajaxRequest3);
And not like this:
而不是这样:
$.when([ajaxRequest1, ajaxRequest2, ajaxRequest3]);
回答by Adolph Trudeau
I like hvgotcodes' idea. My suggestion is to add a generic incrementer that compares the number complete to the number needed and then runs the final callback. This could be built into the final callback.
我喜欢 hvgotcodes 的想法。我的建议是添加一个通用增量器,将完成的数字与所需的数字进行比较,然后运行最终回调。这可以内置到最终回调中。
var sync = {
callbacksToComplete = 3,
callbacksCompleted = 0,
addCallbackInstance = function(){
this.callbacksCompleted++;
if(callbacksCompleted == callbacksToComplete) {
doFinalCallBack();
}
}
};
[Edited to reflect name updates.]
[已编辑以反映名称更新。]
回答by hvgotcodes
EDIT -- perhaps the best option would be to create a service endpoint that does everything the three requests do. That way you only have to do one request, and all the data is where you need it to be in the response. If you find you are doing the same 3 requests over and over again, you will probably want to go this route. It is often a good design decision to set up a facade service on the server that lumps commonly used smaller server actions together. Just an idea.
编辑——也许最好的选择是创建一个服务端点来完成三个请求所做的一切。这样你只需要做一个请求,所有的数据都在你需要的地方。如果你发现你一遍又一遍地做同样的 3 个请求,你可能会想要走这条路。在服务器上设置一个外观服务,将常用的较小的服务器操作集中在一起,这通常是一个很好的设计决策。只是一个想法。
one way to do it would be to create a 'sync' object in your click handler before the ajax calls. Something like
一种方法是在 ajax 调用之前在单击处理程序中创建一个“同步”对象。就像是
var sync = {
count: 0
}
The sync will be bound to the scope of the success calls automatically (closure). In the success handler, you increment the count, and if it is 3 you can call the other function.
同步将自动绑定到成功调用的范围(关闭)。在成功处理程序中,您增加计数,如果是 3,您可以调用另一个函数。
Alternatively, you could do something like
或者,你可以做类似的事情
var sync = {
success1Complete: false,
...
success3Complete: false,
}
when each success is executed, it would change the value in the sync to true. You would have to check the sync to make sure that all three are true before proceeding.
当每次成功执行时,它会将同步中的值更改为 true。在继续之前,您必须检查同步以确保所有三个都是正确的。
Note the case where one of your xhrs does not return success -- you need to account for that.
请注意其中一个 xhrs 没有返回成功的情况——您需要考虑到这一点。
Yet another option would be to always call the final function in your success handlers, and have it access the sync option to determine whether to actually do anything. You would need to make sure the sync is in the scope of that function though.
另一种选择是始终调用成功处理程序中的最终函数,并让它访问同步选项以确定是否实际执行任何操作。不过,您需要确保同步在该功能的范围内。
回答by SBUJOLD
I asked the same question a while ago and got a couple of good answers here: Best way to add a 'callback' after a series of asynchronous XHR calls
不久前我问了同样的问题,在这里得到了几个很好的答案:Best way to add a 'callback' after a series of asynchronous XHR call
回答by P?lOliver
I got some good hints from the answers on this page. I adapted it a bit for my use and thought I could share.
我从本页的答案中得到了一些很好的提示。我对它进行了一些调整以供我使用,并认为我可以分享。
// lets say we have 2 ajax functions that needs to be "synchronized".
// In other words, we want to know when both are completed.
function foo1(callback) {
$.ajax({
url: '/echo/html/',
success: function(data) {
alert('foo1');
callback();
}
});
}
function foo2(callback) {
$.ajax({
url: '/echo/html/',
success: function(data) {
alert('foo2');
callback();
}
});
}
// here is my simplified solution
ajaxSynchronizer = function() {
var funcs = [];
var funcsCompleted = 0;
var callback;
this.add = function(f) {
funcs.push(f);
}
this.synchronizer = function() {
funcsCompleted++;
if (funcsCompleted == funcs.length) {
callback.call(this);
}
}
this.callWhenFinished = function(cb) {
callback = cb;
for (var i = 0; i < funcs.length; i++) {
funcs[i].call(this, this.synchronizer);
}
}
}
// this is the function that is called when both ajax calls are completed.
afterFunction = function() {
alert('All done!');
}
// this is how you set it up
var synchronizer = new ajaxSynchronizer();
synchronizer.add(foo1);
synchronizer.add(foo2);
synchronizer.callWhenFinished(afterFunction);
There are some limitations here, but for my case it was ok. I also found that for more advanced stuff it there is also a AOP plugin (for jQuery) that might be useful: http://code.google.com/p/jquery-aop/
这里有一些限制,但就我而言,没关系。我还发现对于更高级的东西,它还有一个可能有用的 AOP 插件(用于 jQuery):http: //code.google.com/p/jquery-aop/
回答by OscarRyz
I came across this problem today, and this was my naive attempt before watching the accepted answer.
我今天遇到了这个问题,这是我在观看接受的答案之前的幼稚尝试。
<script>
function main() {
var a, b, c
var one = function() {
if ( a != undefined && b != undefined && c != undefined ) {
alert("Ok")
} else {
alert( "?? ")
}
}
fakeAjaxCall( function() {
a = "two"
one()
} )
fakeAjaxCall( function() {
b = "three"
one()
} )
fakeAjaxCall( function() {
c = "four"
one()
} )
}
function fakeAjaxCall( a ) {
a()
}
main()
</script>
回答by sic
Ok, this is old but please let me contribute my solution :)
好的,这是旧的,但请让我贡献我的解决方案:)
function sync( callback ){
syncCount--;
if ( syncCount < 1 ) callback();
}
function allFinished(){ .............. }
window.syncCount = 2;
$.ajax({
url: 'url',
success: function(data) {
sync( allFinished );
}
});
someFunctionWithCallback( function(){ sync( allFinished ); } )
It works also with functions that have a callback. You set the syncCount and you call the function sync(...) in the callback of every action.
它也适用于具有回调的函数。您设置了syncCount 并在每个操作的回调中调用函数sync(...)。