2015-12-07 16 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()以反映您所选择的用户体验。
相关问题