多个ajax调用的jQuery回调

时间:2010-12-06 17:02:40

标签: jquery ajax callback

我想在点击事件中进行三次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*/});
});

14 个答案:

答案 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){},[...]);

Example of deferred here

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调用进行定义。这是组件(和详细文档):

DPAJAX at 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”解决方案)不同,此方法不会强制进行调用的单线程 - 每个解决方案仍然会像快速(或慢速)一样运行环境允许,但只有在完成所有操作时才会调用单个处理程序。它还支持设置超时值和重试尝试,如果您的服务有点冒险。

我发现它非常有用(从代码的角度来理解它非常简单)。没有更多的链接,不再计算呼叫和节省输出。只需“设置并忘记它”。

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

我很抱歉,但我无法解释我写的内容因为我是一个韩语,甚至不会用英语说一句话。但我认为你很容易理解它。