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