多个 ajax 调用的 jQuery 回调

我想在一个点击事件中打三个 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*/});
});
185455 次浏览

编辑——也许最好的选择是创建一个服务端点,该端点完成这三个请求所做的所有工作。这样,您只需要执行一个请求,并且所有数据都在响应中需要它的位置。如果你发现你正在一遍又一遍地做同样的3个请求,你可能会想走这条路线。在服务器上设置 facade 服务,将通常使用的较小服务器操作集中在一起,这通常是一个很好的设计决策。只是个想法。


一种方法是在 ajax 调用之前在您的 click 处理程序中创建一个“ sync”对象。差不多

var sync = {
count: 0
}

Sync 将自动绑定到成功调用的范围(闭包)。在成功处理程序中,可以递增计数,如果是3,则可以调用另一个函数。

或者,你可以这样做

var sync = {
success1Complete: false,
...
success3Complete: false,
}

当每次成功执行时,它会将 sync 中的值更改为 true。在继续之前,您必须检查同步以确保所有三个都为真。

注意其中一个 xhrs 没有返回成功的情况——您需要考虑到这一点。

另一种选择是始终调用成功处理程序中的 final 函数,并让它访问 sync 选项以确定是否要实际执行任何操作。但是,您需要确保 sync 在该函数的作用域内。

我喜欢这个主意。我的建议是添加一个通用的增量,将完成的数字与所需的数字进行比较,然后运行最终的回调。这可以内置到最终回调中。

var sync = {
callbacksToComplete = 3,
callbacksCompleted = 0,
addCallbackInstance = function(){
this.callbacksCompleted++;
if(callbacksCompleted == callbacksToComplete) {
doFinalCallBack();
}
}
};

[根据姓名更新进行了编辑。]

$.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',
....
....
}
}
});

对不起,我不能解释我写了什么,因为我是一个韩国人,甚至不会说一个英语单词。但我觉得你很容易理解。

我自己也不觉得需要什么东西。简单有一个变量是一个整数。当您开始一个请求时,递增该数字。当一个完成,递减它。当它为零时,没有正在进行的请求,所以您完成了。

$('#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
}
});
});

我刚才问了同样的问题,得到了几个不错的答案: 在一系列异步 XHR 调用之后添加回调函数的最佳方法

下面是我编写的一个回调对象,您可以设置一个回调一旦完成就激活,或者让每个回调都有自己的回调,并在完成一次后激活它们:

通知

由于 jQuery 1.5 + ,您可以使用另一个答案中描述的延迟方法:

  $.when($.ajax(), [...]).then(function(results){},[...]);

在这里推迟的例子

对于 jQuery < 1.5,如果需要在未知时间触发 ajax 调用,可以使用以下两个按钮: 点击两个按钮后发射

[使用方法]

单身回调一旦完成: 工作示例

// 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);
}
});

每个都有完成时的 他们自己的回调: 工作示例

//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);
};
};
})();

我从这一页的答案中得到了一些很好的提示。我对它进行了一些改编,以供自己使用,并认为我可以与他人分享。

// 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/”rel = “ nofollow”> http://code.google.com/p/jQuery-AOP/

我今天碰到了这个问题,这是我在看到公认的答案之前的天真尝试。

<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>

看起来您已经得到了这个问题的一些答案,但是我认为这里有一些值得一提的东西,它将极大地简化您的代码。JQuery 在 v1.5中引入了 $.when。看起来像是:

$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
//this callback will be fired once all ajax calls have finished.
});

这里没提到,希望能有帮助。

它不是 jquery (看起来 jquery 有一个可行的解决方案) ,而是另一个选项... ..。

我在使用 SharePoint Web 服务时也遇到过类似的问题——通常需要从多个来源提取数据,以便为单个进程生成输入。

为了解决这个问题,我将这种功能嵌入到我的 AJAX 抽象库中。您可以轻松地定义一个请求,该请求在完成时将触发一组处理程序。然而,每个请求都可以用多个 http 调用定义。下面是组件(和详细文档) :

Depressedpress.com

这个简单的示例创建一个带有三个调用的请求,然后按照调用顺序将该信息传递给一个处理程序:

    // 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”解决方案)不同的是,只要这个方法不强制单线程正在进行的调用——每个调用仍然会在环境允许的范围内尽可能快地(或尽可能慢地)运行,但是只有当所有调用都完成时,才会调用单个处理程序。它还支持设置超时值,如果服务有点不稳定,还支持重试尝试。

我发现它非常有用(从代码的角度来理解也非常简单)。不再需要链接,不再需要计数调用和保存输出。只是“设置它,忘记它”。

async   : false,

默认情况下,所有请求都是异步发送的(也就是说,默认情况下设置为 true)。如果需要同步请求,请将此选项设置为 false。跨域请求和 dataType: "jsonp"请求不支持同步操作。请注意,同步请求可能会暂时锁定浏览器,在请求处于活动状态时禁用任何操作。从 JQuery 1.8开始,不推荐使用 async: falseJqXHR($.Deferred) ; 您必须使用 成功/错误/完成回调选项,而不是使用 JqXHR对象的相应方法,如 jqXHR.done()或不推荐使用的 jqXHR.success()

值得注意的是,由于 $.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);


});

使用 传播语法,您现在可以这样编写代码:

$.when(...requests).then((...responses) => {
// do something with responses
})

这是因为 $.when接受这样的参数

$.when(ajaxRequest1, ajaxRequest2, ajaxRequest3);

不是这样的:

$.when([ajaxRequest1, ajaxRequest2, ajaxRequest3]);

好吧,这是旧的,但请让我贡献我的解决方案:)

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 (...)。

我找到了一种更简单的方法,不需要安排队列的额外方法。

JS

$.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 (ajax1.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);
?>

PHP (ajax2.PHP)

<?php
//catch up callbackmethod
$cb=$_POST['cb'];//is 'method2'


$json[] = array(
"cb" => $cb,
"value" => "ajax2"
);


//encoding array in JSON format
echo json_encode($json);
?>