如何在继续之前构建这些嵌套的异步请求以完成批处理
How to structure these nested asynchronous requests to complete a batch before proceeding?
我需要做一个主要的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
以供后续使用?
如何构建这些不同的 AJAX 请求,以便代码 执行将等到 ajaxFunction 完成并返回 主要结果用于后续使用?
你不能,你也不会。 Javascript 不会"等待"异步操作完成。 相反,您将要在异步操作完成后运行的代码移动到回调中,然后在异步操作完成时调用该回调。 无论是使用纯异步回调还是作为承诺一部分的结构化回调,都是如此。
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()
,因为在将重复调用的函数中插入事件处理程序可能是错误的设计(因为它最终会创建多个相同的事件处理程序(。 如果你确定这是正确的做法,你可以把它插回去,但对我来说它看起来不对。
这通常是使用承诺的好地方,但你的代码有点抽象,无法准确地向你展示如何使用承诺。 我们需要看到 ajaxFetchingFunction1()
和 ajaxFetchingFunction2()
的真实代码来说明如何使用 promise 来做到这一点,因为这些异步函数需要创建和返回 promise。 如果你在它们内部使用jQuery ajax,那么这将很容易,因为jQuery已经为ajax调用创建了一个承诺。
如果修改了 ajaxFetchingFunction1()
和 ajaxFetchingFunction2()
以返回 promise,那么您可以执行以下操作:
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
}
});
});
承诺使处理多个 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()
作为 then 回调在语法上很方便,尽管它(可能(是同步的
样本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()
以反映您选择的用户体验。
- 如何使用异步模块的请求
- Node.js cors请求-异步示例不起作用
- 如果需要登录,Angularjs$http拦截器会暂停异步请求
- 使用异步模块的Express + Mongoose请求处理程序的更简洁的方法
- 将 jQuery UI 日期选择器与异步 AJAX 请求一起使用
- Angularjs的异步API请求
- NodeJS无法异步发出GET请求
- RxJS异步请求更新
- 异步HTTP(ajax)请求在脚本标记中有效,但在js文件中无效
- Node js中间件,用于向mongo发出异步请求
- AJAX-如何在不冻结浏览器的情况下逐个发出异步请求
- 从CORS请求中捕获异步异常
- 如何等待异步请求完成
- 异步xml请求不会;t返回
- 在继续之前,请确保异步GET/POST请求已完成
- 如何像Ember.js那样抽象ajax请求的异步行为
- 异步http请求服务
- 为什么Chrome似乎异步请求Javascript文件
- 使用异步请求多个网址
- 如何使 AJAX 请求异步