2015-05-07 33 views
3

我需要等到我所有的ajax函数都完成了,然后继续执行。等到所有的ajax请求都完成

我的特殊情况是,我需要在提交表单之前先翻译表单中的某些字段。我通过ajax调用将它们翻译为外部网站。取决于我需要做更多或更少翻译的形式中的一些值。当所有的翻译完成后(如果有的话),我必须用ajax验证表单,如果有效,然后提交。

这是我的aproach:
首先,我必须发送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输入在翻译功能开始时增加,在结束时减少。

+0

$(“#form”)。submit();该代码应该做什么? –

+0

尝试使用递归setTimeout而不是使用while循环。 while循环锁定线程,因此无法从#ajaxCounter获取新数据。 –

+0

我很努力去理解代码应该做什么 – garryp

回答

12

您可以使用从$.ajax调用返回的deferred对象以更简洁的方式实现此目的。首先,你应该得到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... 
}); 
+2

这应该是被接受的答案 – devnull69

+2

这是一个优雅的解决方案 –

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

不清楚代码与原始文章的不同之处。请尝试描述您的更改。 –

+0

与原帖不同的是,我把回调放在那里,而不是while循环来检查ajaxCounter的增量。但我只是意识到它通过translatable_fields循环。因此,在每次回调之后,我们可以比较多少个ajax返回与translatable_fields.length的比较。 –

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

为此,您可以使用延迟的对象,但你并不需要使用$.when.apply一个数组,如果你是只对最终完成感兴趣。

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

链平行的承诺

更改您的翻译返回阿贾克斯承诺:

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调用创建一个额外的承诺,但开销非常小,结果代码非常简单。
+0

@Maurice Perry:你喜欢*优雅*,我会对你对这个选择的看法感兴趣:) –