等到所有ajax请求完成

时间:2021-09-26 19:44:31

I need to wait until all my ajax functions are done, and then continue the exectution.

我需要等到我的所有ajax功能完成后再继续执行。

My particular case is that I need to translate some fields in a form before submitting it. I translate them with an ajax call to an external site. Depending on some values in the form i would need to do more or less translations. When all the translations are done (if any) I have to validate the form with ajax, and if its valid, then submit.

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

This is my aproach:
First, I have a function that sends the ajax call and do stuff with the data received:

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

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

Then, when the form is to be submitted I execute the following code:

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

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

The problem is that the while loop in the submit function never ends.

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

If I execute the code without the while loop I can see the ajaxCounter input increasing when the translation functions start and decreasing when they end.

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

4 个解决方案

#1


12  

You can achieve this in a much neater fashion using the deferred objects returned from a $.ajax call. First you should get the translate() function to return the deferred:

您可以使用从$ .ajax调用返回的延迟对象以更整洁的方式实现此目的。首先你应该得到translate()函数来返回延迟:

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

Then you can put all those promises in to a single array:

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

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

Then you can apply that array to $.when:

然后你可以将该数组应用于$ .when:

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

#2


1  

You can do this using deferred objects, but you do not need to use $.when.apply with an array if you are only interested in the final completion.

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

Instead you can chain parallel promises using the pattern promise = $.when(promise, another promise)

相反,你可以使用模式promise = $ .when(承诺,另一个承诺)链接并行承诺

Change your translate to return the Ajax promise:

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

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

and your promise loop simply becomes:

而你的承诺循环变成:

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

Notes:

  • This does create an extra promise per call to $.when, but the overhead is very small and the resulting code is quite simple.
  • 这确实为每次调用$ .when创建了额外的承诺,但是开销非常小,结果代码非常简单。

#3


0  

No, you can't just loop like this: the callbacks would never get a chance to be called.

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

I would do something like this:

我会做这样的事情:

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

and then:

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

#4


-2  

You can use callback

你可以使用回调

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

And pass your after ajax code to it

并将你的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;
        });
    });
});

#1


12  

You can achieve this in a much neater fashion using the deferred objects returned from a $.ajax call. First you should get the translate() function to return the deferred:

您可以使用从$ .ajax调用返回的延迟对象以更整洁的方式实现此目的。首先你应该得到translate()函数来返回延迟:

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

Then you can put all those promises in to a single array:

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

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

Then you can apply that array to $.when:

然后你可以将该数组应用于$ .when:

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

#2


1  

You can do this using deferred objects, but you do not need to use $.when.apply with an array if you are only interested in the final completion.

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

Instead you can chain parallel promises using the pattern promise = $.when(promise, another promise)

相反,你可以使用模式promise = $ .when(承诺,另一个承诺)链接并行承诺

Change your translate to return the Ajax promise:

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

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

and your promise loop simply becomes:

而你的承诺循环变成:

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

Notes:

  • This does create an extra promise per call to $.when, but the overhead is very small and the resulting code is quite simple.
  • 这确实为每次调用$ .when创建了额外的承诺,但是开销非常小,结果代码非常简单。

#3


0  

No, you can't just loop like this: the callbacks would never get a chance to be called.

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

I would do something like this:

我会做这样的事情:

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

and then:

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

#4


-2  

You can use callback

你可以使用回调

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

And pass your after ajax code to it

并将你的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;
        });
    });
});