2015-05-07 38 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:你喜歡*優雅*,我會對你對這個選擇的看法感興趣:) –