我想在点击事件中进行三次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*/});
});
答案 0 :(得分:141)
看起来你已经得到了一些答案,不过我觉得这里有一些值得一提的东西会大大简化你的代码。 jQuery在v1.5中引入了$.when
。它看起来像:
$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
//this callback will be fired once all ajax calls have finished.
});
这里没有看到它,希望它有所帮助。
答案 1 :(得分:98)
这是我写的一个回调对象,你可以将一个回调设置为一旦完成后触发,或让每个回调都有自己的回调并在完成后全部触发:
注意
从jQuery 1.5+开始,您可以使用另一个答案中描述的延迟方法:
$.when($.ajax(), [...]).then(function(results){},[...]);
for jQuery< 1.5以下内容将起作用,或者如果您需要在未知时间触发ajax调用,如下所示,并带有两个按钮:fired after both buttons are clicked
<强> [使用方法] 强>
完成后单次回调: 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);
}
});
完成后,每个人都有自己的回调: 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');
});
}
});
[守则]
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);
};
};
})();
答案 2 :(得分:10)
我自己并没有看到任何对象malarky的需要。简单有一个整数变量。当您启动请求时,请递增该号码。当一个完成时,减少它。当它为零时,没有正在进行的请求,所以你已经完成了。
$('#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
}
});
});
答案 3 :(得分:8)
值得注意的是,由于$.when
期望所有ajax请求都是顺序参数(不是数组),因此通常会.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);
});
一起使用,如下所示:
$.when
这是因为$.when(ajaxRequest1, ajaxRequest2, ajaxRequest3);
接受这样的args
$.when([ajaxRequest1, ajaxRequest2, ajaxRequest3]);
而不是这样:
# three files
file0 = a file log starting at hour mod 0, deleted at hour mod 2
file1 = a file log starting at hour mod 1, deleted at hour mod 0
file2 = a file log starting at hour mod 2, deleted at hour mod 1
# data_file is the last file written to (last hour + this hour)
# current_file is just from the top of this hour (could be 1 record)
# select newest file, and delete file from 2 hours ago
switch (current hour mod 3)
case 0:
current_file = file0;
data_file = file2;
delete file1;
case 1:
current_file = file1;
data_file = file0;
delete file2;
case 2:
current_file = file2;
data_file = file1;
delete file0;
# save data to all files that weren't just deleted
print data to data_file;
print data to current_file;
答案 4 :(得分:4)
我喜欢hvgotcodes的想法。我的建议是添加一个通用的增量器,将完成的数字与所需的数量进行比较,然后运行最终的回调。这可以构建到最终的回调中。
var sync = {
callbacksToComplete = 3,
callbacksCompleted = 0,
addCallbackInstance = function(){
this.callbacksCompleted++;
if(callbacksCompleted == callbacksToComplete) {
doFinalCallBack();
}
}
};
[编辑反映名称更新。]
答案 5 :(得分:3)
编辑 - 也许最好的选择是创建一个服务端点来完成三个请求所做的一切。这样,您只需要执行一个请求,并且所有数据都是您需要它在响应中的位置。如果你发现你一遍又一遍地做同样的3个请求,你可能会想要走这条路。在服务器上设置外观服务通常是一个很好的设计决策,它将常用的较小服务器操作混合在一起。只是一个想法。
一种方法是在ajax调用之前在单击处理程序中创建一个“sync”对象。像
这样的东西var sync = {
count: 0
}
同步将自动绑定到成功调用的范围(闭包)。在成功处理程序中,您递增计数,如果它是3,您可以调用另一个函数。
或者,您可以执行类似
的操作var sync = {
success1Complete: false,
...
success3Complete: false,
}
执行每个成功时,它会将同步中的值更改为true。在继续之前,您必须检查同步以确保所有三个都是真的。
请注意您的某个xhrs未成功返回的情况 - 您需要考虑到这一点。
另一种选择是始终在成功处理程序中调用最终函数,并让它访问同步选项以确定是否实际执行任何操作。您需要确保同步在该功能的范围内。
答案 6 :(得分:0)
前一段时间我问了同样的问题,并在这里得到了几个好的答案:Best way to add a 'callback' after a series of asynchronous XHR calls
答案 7 :(得分:0)
我从这个页面的答案中得到了一些很好的提示。我根据自己的需要对其进行了调整,并认为我可以分享。
// 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);
这里有一些限制,但对我来说这没关系。 我还发现,对于更高级的东西,还有一个可能有用的AOP插件(对于jQuery):http://code.google.com/p/jquery-aop/
答案 8 :(得分:0)
我今天遇到了这个问题,这是我在看到接受的答案之前的天真尝试。
<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>
答案 9 :(得分:0)
这不是jquery(并且看起来jquery有一个可行的解决方案)但是作为另一种选择....
我在使用SharePoint Web服务方面遇到过类似的问题 - 您经常需要从多个来源提取数据,以便为单个进程生成输入。
为了解决这个问题,我将这种功能嵌入到我的AJAX抽象库中。您可以轻松定义一个请求,该请求将在完成时触发一组处理程序。但是,每个请求都可以使用多个http调用进行定义。这是组件(和详细文档):
这个简单的例子创建了一个带有三个调用的请求,然后将这些信息按照调用顺序传递给一个处理程序:
// The handler function
function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) };
// Create the pool
myPool = DP_AJAX.createPool();
// Create the request
myRequest = DP_AJAX.createRequest(AddUp);
// Add the calls to the request
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]);
// Add the request to the pool
myPool.addRequest(myRequest);
请注意,与许多其他解决方案(包括我认为jquery中的“when”解决方案)不同,此方法不会强制进行调用的单线程 - 每个解决方案仍然会像快速(或慢速)一样运行环境允许,但只有在完成所有操作时才会调用单个处理程序。它还支持设置超时值和重试尝试,如果您的服务有点冒险。
我发现它非常有用(从代码的角度来理解它非常简单)。没有更多的链接,不再计算呼叫和节省输出。只需“设置并忘记它”。
答案 10 :(得分:0)
好的,这很旧,但是请让我贡献我的解决方案:)
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 ); } )
它也可用于具有回调的函数。设置syncCount并在每个操作的回调中调用函数sync(...)。
答案 11 :(得分:0)
我找到了一种更简单的方法,不需要额外的安排队列的方法。
JS
to
PHP(ajax1.php)
$.ajax({
type: 'POST',
url: 'ajax1.php',
data:{
id: 1,
cb:'method1'//declaration of callback method of ajax1.php
},
success: function(data){
//catching up values
var data = JSON.parse(data);
var cb=data[0].cb;//here whe catching up the callback 'method1'
eval(cb+"(JSON.stringify(data));");//here we calling method1 and pass all data
}
});
$.ajax({
type: 'POST',
url: 'ajax2.php',
data:{
id: 2,
cb:'method2'//declaration of callback method of ajax2.php
},
success: function(data){
//catching up values
var data = JSON.parse(data);
var cb=data[0].cb;//here whe catching up the callback 'method2'
eval(cb+"(JSON.stringify(data));");//here we calling method2 and pass all data
}
});
//the callback methods
function method1(data){
//here we have our data from ajax1.php
alert("method1 called with data="+data);
//doing stuff we would only do in method1
//..
}
function method2(data){
//here we have our data from ajax2.php
alert("method2 called with data="+data);
//doing stuff we would only do in method2
//..
}
PHP(ajax2.php)
<?php
//catch up callbackmethod
$cb=$_POST['cb'];//is 'method1'
$json[] = array(
"cb" => $cb,
"value" => "ajax1"
);
//encoding array in JSON format
echo json_encode($json);
?>
答案 12 :(得分:-1)
async : false,
默认情况下,所有请求都是异步发送的(默认情况下设置为true)。如果您需要同步请求,请将此选项设置为 false
。跨域请求和dataType: "jsonp"
请求不支持同步操作。请注意,同步请求可能会暂时锁定浏览器,并在请求处于活动状态时禁用任何操作。从 jQuery 1.8 开始,不推荐使用async: false
和 jqXHR ($.Deferred
);您必须使用成功/错误/完整回调选项,而不是 jqXHR 对象的相应方法,例如jqXHR.done()
或已弃用的jqXHR.success()
。
答案 13 :(得分:-2)
$.ajax({type:'POST', url:'www.naver.com', dataType:'text', async:false,
complete:function(xhr, textStatus){},
error:function(xhr, textStatus){},
success:function( data ){
$.ajax({type:'POST',
....
....
success:function(data){
$.ajax({type:'POST',
....
....
}
}
});
我很抱歉,但我无法解释我写的内容因为我是一个韩语,甚至不会用英语说一句话。但我认为你很容易理解它。