1.问题
每个异步校验完成时间不确定,js代码无法及时根据异步校验结果判断是否该提交表单.
2.解法方式
2.1 使用同步
- 同步会等每个请求响应成功才会执行后面的js代码
- 代码简单,效果好
- 同步ajax会锁死页面,用户体验不好,严重的浏览器还会崩溃
$.ajax({
async:false, //同步
});
2.2 使用计数器
- 计数器用于记录异步校验的成功数,只有计数与需要异步校验数量一致才提交表单
- 快速多次点击提交表单按钮可能导致计数出错
- 不推荐使用
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form name="form" method="post" action="https://www.baidu.com">
<!-- 此处省略表单元素标签 -->
<!-- 使用普通按钮代替提交按钮,避免事件触发多次调用checkForm() -->
<input type="button" value="提交" id="btn_submit" onclick="checkForm()"/>
</form>
</body>
<script>
//计数器
var count=0;
//表单提交前的数据校验
function checkForm(){
/*此处省略校验其他普通数据*/
//重置计数器
count=0;
//调用各个异步校验
f1(true);
f2(true);
f3(true);
f4(true);
}
//提交表单
function submitForm(){
if(count==4){
document.form.submit();
}
}
var flag4=false;
//第一个异步校验
//isSubmit是否表单提交前的校验
function f1(isSubmit){
//模拟异步请求到服务器端,延时1秒
setTimeout(function(){
if(isSubmit){
//每个异步校验成功计算器+1,并且判断判断计算器是否满足条件提交表单
count++;
submitForm()
}
},1000);
}
//第二个异步校验
function f2(isSubmit){
//模拟异步请求到服务器端,延时2秒
setTimeout(function(){
if(isSubmit){
count++;
submitForm()
}
},2000);
}
//第三个异步校验
function f3(isSubmit){
//模拟异步请求到服务器端,延时3秒
setTimeout(function(){
if(isSubmit){
count++;
submitForm()
}
},3000);
}
//第四个异步校验
function f4(isSubmit){
//模拟异步请求到服务器端,延时4秒
setTimeout(function(){
if(isSubmit){
count++;
submitForm()
}
},4000);
}
</script>
</html>
2.3 使用标志
- 使用多个变量标志每个异步校验的结果,只有每个标志成功才提交表单
- 标志变量多,但快速多次点击提交表单按钮不会判断错误
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form name="form" method="post" action="https://www.baidu.com">
<!-- 此处省略表单元素标签 -->
<!-- 使用普通按钮代替提交按钮,避免事件触发多次调用checkForm() -->
<input type="button" value="提交" id="btn_submit" onclick="checkForm()"/>
</form>
</body>
<script>
//标志变量
var flag1=false;
var flag2=false;
var flag3=false;
var flag4=false;
//表单提交前的数据校验
function checkForm(){
/*此处省略校验其他普通数据*/
//重置标志
var flag1=false;
var flag2=false;
var flag3=false;
var flag4=false;
//调用各个异步校验
f1(true);
f2(true);
f3(true);
f4(true);
}
//提交表单
function submitForm(){
if(flag1&&flag2&&flag3&&flag4){
document.form.submit();
}
}
//第一个异步校验
//isSubmit是否表单提交前的校验
function f1(isSubmit){
//模拟异步请求到服务器端,延时1秒
setTimeout(function(){
if(isSubmit){
//校验成功把相应的标志设为true,每次校验成功都需要判断所有标志是否能满足提交表单
flag1=true;
submitForm()
}
},1000);
}
//第二个异步校验
function f2(isSubmit){
//模拟异步请求到服务器端,延时2秒
setTimeout(function(){
if(isSubmit){
flag2=true;
submitForm()
}
},2000);
}
//第三个异步校验
function f3(isSubmit){
//模拟异步请求到服务器端,延时3秒
setTimeout(function(){
if(isSubmit){
flag3=true;
submitForm()
}
},3000);
}
//第四个异步校验
function f4(isSubmit){
//模拟异步请求到服务器端,延时4秒
setTimeout(function(){
if(isSubmit){
flag4=true;
submitForm()
}
},4000);
}
</script>
</html>
2.4使用位或
- 位或:两个整数的对应二进制位,如果有一个为1,则结果为1,否则,结果为0
- 二进制位所有位只有一个1的数:1,2,4,8,16,32…等等,所以这些数进行位或相应的位变成1,算数结果等同于求和(可以达到2.2的计数器效果)
- 1,2,4,8,16,32…等数的每个位的1都是唯一的,所以必须每个数都被位或了才能使最终结果的每个位都是1,这些数多次被位或结果是不变的,所以就可以达到2.3的标志效果
- 该方式不够直观,当代码位置比较乱时可能会漏掉或计算错误
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form name="form" method="post" action="https://www.baidu.com">
<!-- 此处省略表单元素标签 -->
<!-- 使用普通按钮代替提交按钮,避免事件触发多次调用checkForm() -->
<input type="button" value="提交" id="btn_submit" onclick="checkForm()"/>
</form>
</body>
<script>
//位或结果
var result=0;
//表单提交前的数据校验
function checkForm(){
/*此处省略校验其他普通数据*/
//重置位或结果
result=0
//调用各个异步校验
f1(true);
f2(true);
f3(true);
f4(true);
}
//提交表单
function submitForm(){
// 1|2|4|8=15
if(result==15){
document.form.submit();
}
}
//第一个异步校验
//isSubmit是否表单提交前的校验
function f1(isSubmit){
//模拟异步请求到服务器端,延时1秒
setTimeout(function(){
if(isSubmit){
//校验成功位或相应数字(1,2,4,8),每次校验成功都需要判断是否能满足提交表单
result=result|1;
submitForm()
}
},1000);
}
//第二个异步校验
function f2(isSubmit){
//模拟异步请求到服务器端,延时2秒
setTimeout(function(){
if(isSubmit){
result=result|2;
submitForm()
}
},2000);
}
//第三个异步校验
function f3(isSubmit){
//模拟异步请求到服务器端,延时3秒
setTimeout(function(){
if(isSubmit){
result=result|4;
submitForm()
}
},3000);
}
//第四个异步校验
function f4(isSubmit){
//模拟异步请求到服务器端,延时4秒
setTimeout(function(){
if(isSubmit){
result=result|8;
submitForm()
}
},4000);
}
</script>
</html>