等到所有的ajax请求都完成

时间:2015-05-07 11:29:33

标签: javascript jquery ajax forms

我需要等到我的所有ajax功能都完成,然后继续执行exectution。

我的具体情况是我需要在提交之前翻译表单中的某些字段。我通过对外部站点的ajax调用来翻译它们。根据表单中的某些值,我需要做更多或更少的翻译。完成所有翻译后(如果有的话)我必须用ajax验证表格,如果有效,则提交。

这是我的理由:
首先,我有一个函数发送ajax调用并对收到的数据做一些事情:

function translate(...) {
    $("#ajaxCounter").val(parseInt($("#ajaxCounter").val()) + 1);
    $.ajax({
        ...
        success:function(data) {
            ...
            $("#ajacCounter").val(parseInt($("#ajaxCounter").val()) - 1);
        }
    });

然后,当要提交表单时,我执行以下代码:

$("#form").submit(function() {
    translatable_fields.each(function() {
        translate(...);
    });
    while (parseInt($("#ajaxCounter").val()) > 0) { null; }
    if (!(this).hasClass('ready')) {
        $.ajax({
            //validation
            success: function(data) {
                if (data['isValid']) {
                    $("#form").addClass('ready');
                    $("#form").submit();
                }
            }
        });
    }
    return true;
});

问题是提交函数中的while循环永远不会结束。

如果我执行没有while循环的代码,我可以看到ajaxCounter输入在翻译函数开始时增加,在结束时减少。

4 个答案:

答案 0 :(得分:13)

您可以使用deferred调用返回的$.ajax对象以更整洁的方式实现此目的。首先,您应该获得translate()函数以返回deferred

function translate(...){
    return $.ajax({
        // settings...
    });
});

然后你可以将所有这些承诺放在一个数组中:

var requests = [];
translatable_fields.each(function(){
    requests.push(translate(...));
});

然后您可以apply将该数组$.when

$.when.apply($, requests).done(function(schemas) {
     console.log("All requests complete");
    // do something...
});

答案 1 :(得分:1)

您可以使用延迟对象执行此操作,但如果您只对最终完成感兴趣,则不需要将$.when.apply与数组一起使用。

相反,您可以使用模式promise = $.when(promise, another promise)

链接并行承诺

更改您的翻译以返回Ajax承诺:

function translate(...) {
    ...
    return $.ajax({
        ...
    });
}

并且您的承诺循环变为:

var promise; // Start with an undefined promise - which is the same as a resolved promise for $.when
translatable_fields.each(function() {
    promise = $.when(promise, translate(...));
});

// Wait for all promises to complete
promise.done(function(){
    // now do the final code after all the ajax calls complete
});

注意:

  • 这确实为每个$.when调用创建了一个额外的承诺,但开销非常小,结果代码非常简单。

答案 2 :(得分:0)

不,你不能像这样循环:回调永远不会被调用。

我会做这样的事情:

function translateAllFields(done) {
    var requestsInProgress = 0, doneCalled = false;
    translatable_fields.each(function () {
        ++requestsInProgress;
        $.ajax({
            //...
            success: function (data) {
                //...
                $("#ajacCounter").val(parseInt($("#ajaxCounter").val()) - 1);
            }
        }).always(function () {
            if (--requestsInProgress === 0) {
                done();
                doneCalled = true;
            }
        });
    });
    if (requestsInProgress === 0 && !doneCalled) {
        // in case translatable_fields was empty
        done();
    }
}

然后:

$("#form").submit(function (e) {
    if (!(this).hasClass('ready')) {
        e.preventDefault();
        e.stopPropagation();
        translateAllFields(function() {
            $.ajax({
                //validation
                success: function (data) {
                    if (data['isValid']) {
                        $("#form").addClass('ready');
                        $("#form").submit();
                    }
                }
            });
        });
    }
});

答案 3 :(得分:-2)

您可以使用回调

function translate(..., callback) {
    $.ajax({
        ...
        success:function(data) {
            ...
            callback(data);
        }
    });
};

将你的ajax代码传递给它

$("#form").submit(function() {
    translatable_fields.each(function() {
        translate(..., function(result){

            if (!(this).hasClass('ready')) {
                $.ajax({
                    //validation
                    success: function(data) {
                        if (data['isValid']) {
                            $("#form").addClass('ready');
                            $("#form").submit();
                        }
                    }
                });
            }
            return true;
        });
    });
});