开发中经常会遇到表单校验依赖服务端的情况,当只有一个两个ajax校验的时候通过回调函数来处理还能接受。但是当有n多个ajax校验,或者校验次数不已知的时候前端代码如果还用回调进行嵌套的话会是毁灭性的。讨论这个问题的时候我们有个前提是:有些原因让你很难或者不能一个ajax请求解决所有校验
下面看几个写法:
校验次数确定的嵌套写法:
<!--config为ajax请求的配置,这里为了明确代码结构不写具体内容-->
<!--校验1-->
$.ajax(config).success(function(data){
if(data.success==true){
<!--校验2-->
$.ajax(config).success(function(data){
if(data.success==true){
<!--校验3-->
$.ajax(config).success(function(data){
...
if(data.success==true){
<!--校验成功提交数据-->
dosubmit()
}
})
}
})
}
})
以上还是需要校验的次数确定的。如果校验次数是动态的。代码结构还要再麻烦;你可以先想一下自己有没有办法来解决不定次数个ajax校验。
首先你可能想到的是把ajax改成同步的在循环中校验,但是你别忘了ajax是优势是异步的,改成同步会导致锁住ui,降低用户体验。 那么如何进行异步的处理呢。
校验次数不确定循环写法:
<!--config为ajax请求的配置,这里为了明确代码结构不写具体内容-->
<!--校验1-->
var validateList=[{param1:1},{param2:2},...,{paramN:n}]
var resultList=[]
for(var i=0;i<validateList.length;i++){
<!--假设config中的url是一样的,如果不一样还需要自行处理-->
$.ajax(config).success(function(data){
resultList.push(data);
<!--如果结果长度和校验长度相同了说明是最后一次请求了-->
if(resultList.length===validateList.length){
<!--这里对返回的结果进行判断-->
for(var t=0;t<validateList.length;t++){
if(t.success==false){
alert('校验不通过')
return false;
}
}
<!--没有false的情况-->
dosubmit();
}
})
}
以上代码还是做了简化的,实际可能每个返回值的处理逻辑都不一样,每个校验的url等等ajax配置还都不一样,代码量和复杂度可能还会翻倍;
那么如何进行优雅的处理呢?
接下来用到jquery的Deferred或者es6的Promise来解决这个困境,二者有很大的相似性。具体取决于你自己的要求。这里只介绍deferred处理方式
<!--首先把每个校验封装成一个个ajax对象-->
var validate1=$.ajax(config1);
var validate2=$.ajax(config2);
var validate3=$.ajax(config3);
...
var validaten=$.ajax(confign);
<!--放到一个数组里-->
var validateArr=[validate1,validate2,...,validaten];
<!--关键在这里,通过jquery的when.apply().done来注册回调函数,argsj就是每个校验逻辑的响应值-->
$.when.apply($, validateArr).done(function (...args) {
for (var i = 0; i < args.length; i++) {
if (!args[i].success) {
return false
}
}
<!--所有校验通过进行处理-->
dosubmit()
})
写到这里你可能会问说好的Deferred呢,其实jquery的ajax就是基于Deferred实现的,上面每一个validate都是一个deferred对象;当然你也可以自行实现Deferred对象来处理此类问题,具体自行思考下(小提示:可以在ajax success中进行resolve即可)
这种写法代码结构更加清晰,把不同的部分封装到了独立的ajax对象中。更具有扩展性,更易于应对变化。如果每个请求的返回值不一样也可以通过config中添加ajax的dataFilter进行处理为统一格式;希望大家都能写出更优雅的代码,谢谢大家阅读。不足之处请指正。