2015-12-07 38 views
0

我需要做一個主要的AJAX表單提交。但是,在繼續提交主體之前,我想要執行一系列其他初步形式的提交和AJAX請求。如何構建這些嵌套的異步請求以在繼續之前完成批處理?

下面是這個想法,但有很多僞代碼。我想打電話給ajaxFunction如圖所示,完成所有工作,然後與主表單提交着手:

$('#mainform').submit(function(e){ 
    e.preventDefault(); 
    var main = this; 

    var data = $('#section :input', main).serialize(); 

    //preliminary nested ajax requests 
    var mainresult = ajaxFunction('arg1', 'arg2'); 


    alert("All preliminary AJAX done, proceeding..."); 

    if(mainresult){  
     //final ajax 
     $.post('mainurl', data, function(result){ 
      console.log(result); 
     }); 
    }else{ 
     //do nothing 
    } 
}); 


function ajaxFunction(param1, param2){ 
    //ajax1 
    ajaxFetchingFunction1('url1', function(){ 
     //ajax2 
     ajaxFetchingFunction2('url2', function(){ 
      //submit handler 
      $('#anotherform').submit(function(){ 
       if(someparam === 1){ 
        return true; 
       }else{ 
        return false; 
       } 
      }); 
     }); 
    }); 

}

因爲它是現在,我知道如預期,因爲它不會工作所有的異步嵌套的AJAX調用。我得到的結果是alert("All preliminary AJAX done, proceeding...");甚至在ajaxFunction的任何AJAX調用之前執行。

我相信這只是一種爲延遲/承諾概念引入的場景(「回調地獄」),但我一直在努力圍繞這個方向。我如何構造這些不同的AJAX請求,以便代碼執行將等到ajaxFunction完成並返回mainresult以供後續使用?

回答

3

我如何組織這些不同的AJAX請求,這樣代碼 執行會等到ajaxFunction完成並返回 mainresult供後續使用?

你不能也不會。 JavaScript不會「等待」異步操作來完成。相反,您將在異步操作完成後要運行的代碼移入一個回調,然後在異步操作完成時調用該回調。無論使用簡單的異步回調還是作爲promise的一部分的結構化回調,情況都是如此。

Javascript中的異步編程需要重新思考和重構控制流程,以便在異步操作完成後要運行的內容放入回調函數中,而不是僅在下一行代碼中順序執行。異步操作通過一系列回調進行順序鏈接。承諾是簡化這些回調的管理的手段,特別是簡化錯誤的傳播和/或多個異步操作的同步。


如果你堅持回調,那麼你就可以完成回調溝通ajaxFunction()完成:

function ajaxFunction(param1, param2, doneCallback){ 
    //ajax1 
    ajaxFetchingFunction1('url1', function(){ 
     //ajax2 
     ajaxFetchingFunction2('url2', function(){ 
      doneCallback(someResult); 
     }); 
    }); 
} 

而且,當時在這裏使用它:

$('#mainform').submit(function(e){ 
    e.preventDefault(); 
    var main = this; 

    var data = $('#section :input', main).serialize(); 

    //preliminary nested ajax requests 
    ajaxFunction('arg1', 'arg2', function(result) { 
     // process result here 
     alert("All preliminary AJAX done, proceeding..."); 

     if(result){  
      //final ajax 
      $.post('mainurl', data, function(result){ 
       console.log(result); 
      }); 
     }else{ 
      //do nothing 
     } 
    }); 
}); 

注:我刪除你的代碼$('#anotherform').submit(),因爲在一個將被重複調用的函數中插入一個事件處理程序可能是錯誤的設計(因爲它最終會創建多個標識符cal事件處理程序)。如果您確信這是正確的做法,您可以將其插回,但它對我來說看起來不對。


這通常是使用承諾的好地方,但你的代碼是一個有點抽象告訴你究竟是如何使用的承諾。我們需要查看ajaxFetchingFunction1()ajaxFetchingFunction2()的真實代碼,以說明如何使用承諾進行工作,因爲這些異步函數需要創建並返回承諾。如果你在裏面使用jQuery ajax,那麼這很容易,因爲jQuery已經爲ajax調用創建了一個承諾。

如果同時ajaxFetchingFunction1()ajaxFetchingFunction2()被修改爲返回一個承諾,那麼你可以做這樣的事情:

function ajaxFunction(param1, param2){ 
    return ajaxFetchingFunction1('url1').then(function() { 
     return ajaxFetchingFunction2('url2'); 
    }); 
} 

而且,當時在這裏使用它:

$('#mainform').submit(function(e){ 
    e.preventDefault(); 
    var main = this; 

    var data = $('#section :input', main).serialize(); 

    //preliminary nested ajax requests 
    ajaxFunction('arg1', 'arg2').then(function(result) { 
     // process result here 
     alert("All preliminary AJAX done, proceeding..."); 

     if(result){  
      //final ajax 
      $.post('mainurl', data, function(result){ 
       console.log(result); 
      }); 
     }else{ 
      //do nothing 
     } 
    }); 
}); 
+0

感謝您的時間和麻煩。我在「消化」你的答案。 –

2

承諾作出的處理多個Ajax請求確實很微不足道,但是「部分形式」對GUI設計的影響可能更具挑戰性。你必須要考慮的事情,如:

  • 一種形式分爲幾個部分,或每部分一種形式?
  • 從一開始就顯示所有部分,或逐步顯示它們?
  • 鎖定以前驗證過的部分以防止驗證後干預?
  • 重新驗證每個階段的所有部分,或只是當前的部分?
  • 一個整體提交按鈕還是每個部分一個?
  • 應如何標記提交按鈕(以幫助用戶瞭解他所參與的過程)?

假設(這是對我的情況,但也許不是OP),我們不知道答案,所有這些問題還沒有,但他們可以體現在兩個功能 - validateAsync()setState(),既其中接受stage參數。

這使我們能夠編寫一個廣義的主例程,以滿足未知的驗證調用和各種GUI設計決策。

這一階段唯一需要的假設是形式/部分的選擇器。讓我們假設它/它們都有class="partialForm"

$('.partialForm').on('submit', function(e) { 
    e.preventDefault(); 
    $.when(setState(1)) // set the initial state, before any validation has occurred. 
    .then(validateAsync.bind(null, 1)).then(setState.bind(null, 2)) 
    .then(validateAsync.bind(null, 2)).then(setState.bind(null, 3)) 
    .then(validateAsync.bind(null, 3)).then(setState.bind(null, 4)) 
    .then(function aggregateAndSubmit() { 
     var allData = ....; // here aggregate all three forms' into one serialization. 
     $.post('mainurl', allData, function(result) { 
      console.log(result); 
     }); 
    }, function(error) { 
     console.log('validation failed at stage: ' + error.message); 
     // on screen message for user ... 
     return $.when(); //inhibit .fail() handler below. 
    }) 
    .fail(function(error) { 
     console.log(error); 
     // on screen message for user ... 
    }); 
}); 

這句法方便在這裏呼籲setState()作爲然後回調雖然它的(可能)同步

樣品validateAsync()

function validateAsync(stage) { 
    var data, jqXHR; 
    switch(stage) { 
     case 1: 
      data = $("#form1").serialize(); 
      jqXHR = $.ajax(...); 
      break; 
     case 2: 
      data = $("#form2").serialize(); 
      jqXHR = $.ajax(...); 
      break; 
     case 3: 
      data = $("#form3").serialize(); 
      jqXHR = $.ajax(...); 
    } 
    return jqXHR.then(null, function() { 
     return new Error(stage); 
    }); 
} 

樣品setState()

function setState(stage) { 
    switch(stage) { 
     case 1: //initial state, ready for input into form1 
      $("#form1").disableForm(false); 
      $("#form2").disableForm(true); 
      $("#form3").disableForm(true); 
     break; 
     case 2: //form1 validated, ready for input into form2 
      $("#form1").disableForm(true); 
      $("#form2").disableForm(false); 
      $("#form3").disableForm(true); 
     break; 
     case 3: //form1 and form2 validated, ready for input into form3 
      $("#form1").disableForm(true); 
      $("#form2").disableForm(true); 
      $("#form3").disableForm(false); 
     break; 
     case 4: //form1, form2 and form3 validated, ready for final submission 
      $("#form1").disableForm(true); 
      $("#form2").disableForm(true); 
      $("#form3").disableForm(true); 
    } 
    return stage; 
} 

書面setState(),將需要jQuery插件.disableForm()

jQuery.fn.disableForm = function(bool) { 
    return this.each(function(i, form) { 
     if(!$(form).is("form")) return true; // continue 
     $(form.elements).each(function(i, el) { 
      el.readOnly = bool; 
     }); 
    }); 
} 

正如我所說,上述validateAsync()setState()只是初步的樣本。至少,你將需要:

  • 割肉出局validateAsync()
  • 修改setState()以反映您所選擇的用戶體驗。
相關問題