在继续之前等待多个异步调用完成

Caf*_*eek 55 javascript jquery asynchronous callback

所以,我有一个加载的页面,并通过jquery.get发出几个请求,用它们的值填充下拉列表.

$(function() {
    LoadCategories($('#Category'));
    LoadPositions($('#Position'));
    LoadDepartments($('#Department'));

    LoadContact();
};
Run Code Online (Sandbox Code Playgroud)

然后调用LoadContact(); 这是另一个调用,当它返回时,它会填充表单上的所有字段.问题是通常,下拉列表并非全部填充,因此,它无法将它们设置为正确的值.

我需要做的是,只要其他方法完成并且回调完成执行,LoadContact就会以某种方式执行.

但是,我不想在下拉填充回调的末尾放置一堆标志,然后检查,并且在调用LoadContact()之前必须进行递归的setTimeout调用检查;

jQuery中有什么东西可以让我说,"当所有这些都完成时执行它."?

更多信息 我正在考虑这些问题

$().executeAfter(
    function () {   // When these are done
        LoadCategories($('#Category'));
        LoadPositions($('#Position'));
        LoadDepartments($('#Department'));
    },
    LoadContact // Do this
);
Run Code Online (Sandbox Code Playgroud)

...它需要跟踪在执行方法期间发生的ajax调用,并且当它们全部完成时,调用LoadContact;

如果我知道如何拦截在该函数中创建的ajax,我可能会编写一个jQuery扩展来执行此操作.

我的解决方案

;(function($) {
    $.fn.executeAfter = function(methods, callback) {

        var stack = [];

        var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            stack.push(url);
        }

        var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            var index = jQuery.inArray(url, stack);

            if (index >= 0) {
                stack.splice(index, 1);
            }

            if (stack.length == 0) {
                callback();
                $this.unbind("ajaxComplete");
            }
        }

        var $this = $(this);

        $this.ajaxSend(trackAjaxSend)
        $this.ajaxComplete(trackAjaxComplete)

        methods();
        $this.unbind("ajaxSend");
    };
})(jQuery);
Run Code Online (Sandbox Code Playgroud)

这会在调用方法时绑定到ajaxSend事件,并保留一个调用的url列表(需要更好的唯一id).然后它从ajaxSend解除绑定,因此只跟踪我们关心的请求.它还绑定到ajaxComplete并在返回时从堆栈中删除项目.当堆栈达到零时,它将执行我们的回调,并取消绑定ajaxComplete事件.

Nic*_*ver 43

你可以.ajaxStop()像这样使用:

$(function() {
  $(document).ajaxStop(function() {
    $(this).unbind("ajaxStop"); //prevent running again when other calls finish
    LoadContact();
  });
  LoadCategories($('#Category'));
  LoadPositions($('#Position'));
  LoadDepartments($('#Department'));
});
Run Code Online (Sandbox Code Playgroud)

这将在所有当前请求完成后运行,然后取消绑定,以便在页面执行中未来的ajax调用时它不会运行.另外,一定要把它放在你的ajax调用之前,这样它就能早点受到限制,但更重要的是.ajaxStart(),但是最好的做法是同时使用它们.


KPD*_*KPD 17

扩展Tom Lianza的答案,$.when()现在是比使用更好的方法.ajaxStop().

唯一需要注意的是,您需要确保在返回a时需要等待的异步方法Deferred object.幸运的是,jQuery ajax调用默认情况下已经这样做了.因此,要从问题中实现场景,需要等待的方法看起来像这样:

function LoadCategories(argument){
    var deferred = $.ajax({
       // ajax setup
    }).then(function(response){ 
       // optional callback to handle this response 
    });
    return deferred;
}
Run Code Online (Sandbox Code Playgroud)

然后在所有三个ajax调用返回后调用LoadContact()并可选地执行它们自己的单独回调:

// setting variables to emphasize that the functions must return deferred objects
var deferred1 = LoadCategories($('#Category'));
var deferred2 = LoadPositions($('#Position'));
var deferred3 = LoadDepartments($('#Department'));

$.when(deferred1, deferred2, deferred3).then(LoadContact);
Run Code Online (Sandbox Code Playgroud)


Tom*_*nza 7

如果您使用的是Jquery 1.5或更高版本,我怀疑Deferred对象是您最好的选择:http: //api.jquery.com/category/deferred-object/

帮助方法,当时,也很不错:http: //api.jquery.com/jQuery.when/