jQuery使用(十二):工具方法之ajax的无忧回调(优雅的代码风格)
- jQuery.ajax()方法的应用
- jQuery.ajax()的无忧回调(优雅的代码风格)
一、jQuery.ajax()方法的应用
jQuery.ajax()实质上就是在ajax的基础上进行了封装,将参数设置,方法调用,数据传输,响应的回调函数等都封装到一个对象中,然后使用这个对象作为jQurey.ajax()的参数调用实现统一配置执行的效果。
jQuery.ajax(object)中的object的常用属性及设置:
- url:请求地址
- type:HTTP的请求方法
- success:请求成功的处理函数(响应的数据会被转换成对象传入处理函数)
- error:当请求失败的处理函数,会传入一个提示对象,其中obj.status为状态码,obj.statusText表示状态说明。
- complete:请求完成以后(无论成功还是失败)的处理函数
- context:改变函数上下文
- timeout:设置本地的请求超时时间(以毫秒计)。
- async:请求采用异步还是同步执行(默认异步)
- dataType:预期的服务器响应的数据类型(json)。
1.Easy Mock模拟jQuery.ajax()请求:
1 $.ajax({ 2 url:'https://easy-mock.com/mock/5c0b4a876162b83fe0a50cb9/person', 3 type:"GET", 4 success:function(res){ 5 $.each(res.data,function(index,ele){ 6 console.log(ele); 7 }) 8 }, 9 error:function(e){ 10 if(e.status == 404){ 11 console.log("我找不到主人要的宝贝。。。哇呜。。。"); 12 } 13 }, 14 complete:function(){ 15 console.log("我完成了任务,快夸我,夸我的人都长得好。"); 16 } 17 });
2.使用context改变函数执行的上下文示例:
1 //html 2 <div class="wrapper"></div> 3 //js 4 $.ajax({ 5 url:'https://easy-mock.com/mock/5c0b4a876162b83fe0a50cb9/person', 6 type:"GET", 7 success:function(res){ 8 console.log(this);////init [div.wrapper, prevObject: init(1), context: document, selector: ".wrapper"] 9 }, 10 context:$('.wrapper'), 11 complete:function(){ 12 console.log(this)//init [div.wrapper, prevObject: init(1), context: document, selector: ".wrapper"] 13 } 14 });
二、jQuery.ajax()的无忧回调(优雅的代码风格)
通过第一部分的分析,好像jQuery.ajax已经全部学会了,no...
对于一个简单的网络请求来说,第一部分无可厚非已经足以,但是在实际开发中,复杂的需求伴随着的是复杂的代码结构和网络情况,如果存在多个网络请求嵌套请求的情况,代码会出现死亡三角的复杂区域,对于后期维护会造成非常大的麻烦。为了更友好的开发维护,jQuery.ajax提供了强大的解决方案,就是jQuery.ajax请求会返回一个Deferred.promise()方法,这个方法提供了友好的ajax不同完成状态的回调函数的添加接口。可能到这里你还不知道我在说什么,接下来看下面这个需求的由ajax产生的死亡三角和其解决方案的两份代码你就明白了,由于篇幅比较大,我将需求和死亡三角代码折叠,提供最后优雅的代码展示:
1 <!-- 一、基础说明 2 code/ code为0时表示正常状态,msg为Ok 3 msg / code为非0时表示异常状态,msg为error 4 data/ 接口返回实体数据 5 二、实体对象 6 power: 7 名称 / 类型/ 备注 8 Power/ String/ 权限 9 movieList: 10 名称 / 类型 / 备注 11 name / String/ 电影名字 12 poster/ String/ 电影封面 13 id / String/ 电影id 14 movieInfo: 15 名称 / 类型 / 备注 16 name / String / 电影名字 17 poster / String / 电影封面 18 direct / String / 导演 19 screewriter/ Array<string>/ 编剧 20 mainActior / Array<string>/ 主演 21 gut / String / 剧情 22 三、接口文档 23 1.权限 24 BaseUrl:https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie 25 URL:/power 26 Type:POST 27 Request: 28 名称 / 类型 / 备注 29 Username/ String/ 用户名 30 Password/ String/ 密码 31 Response: 32 { 33 code:0 34 msg:OK 35 data:power 36 } 37 38 2.电影列表 39 BaseUrl:https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie 40 URL:/movieList 41 Type:GET 42 Response: 43 { 44 code:0 45 msg:OK 46 data:Array <movieList> 47 } 48 49 3.电影详情 50 BaseUrl:https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie 51 URL:/movieInfo 52 Type:GET 53 Request: 54 名称 / 类型 / 备注 55 movieId/ Number/ 电影的ID 56 Response: 57 { 58 code:0 59 msg:OK 60 data:movieInfo 61 }
1 <style type="text/css" media="screen"> 2 *{ 3 padding: 0px; 4 margin: 0px auto; 5 } 6 .tpl{ 7 display: none; 8 } 9 .wrapper{ 10 overflow: hidden; 11 border: 2px solid black; 12 width: 600px; 13 margin: 100px auto 0px; 14 } 15 .movieSection{ 16 float: left; 17 width: 180px; 18 height: 180px; 19 padding: 10px; 20 } 21 .movieSection img{ 22 width: 100%; 23 height: 150px; 24 cursor: pointer; 25 } 26 .movieSection h3{ 27 height: 30px; 28 } 29 </style> 30 <div class="wrapper"> 31 <div class="tpl"> 32 <img src=""> 33 <h3 class="movieName"></h3> 34 </div> 35 </div> 36 <script> 37 // 38 $.ajax({ 39 url:'https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/power', 40 type:"POST", 41 data:{ 42 username:"cst", 43 password:"123123" 44 }, 45 success:function(res){ 46 if(res.data.power == 'root'){ 47 //vip 网络地址发送请求 48 $.ajax({ 49 url:'https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/movieList', 50 type:'GET', 51 success:function(res){ 52 var data = res.data; 53 var $Wrapper = $('.wrapper'); 54 $.each(data,function(index,ele){ 55 // ele.name ele.poste 56 var $MovieSection = $('.tpl').clone().removeClass('tpl').addClass('movieSection'); 57 $MovieSection.data({id:ele.id}).on('click',function(){ 58 $.ajax({ 59 url:"https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/movieInfo", 60 type:'GET', 61 data:{ 62 movieId:$(this).data('id') 63 }, 64 success:function(res){ 65 var data = res.data; 66 var direct = data.direct; 67 var gut = data.gut; 68 var mainActor = data.mainActor; 69 var screenWriter = data.screenwriter; 70 var htmlStr = '<div class="mask">\ 71 <p>导演:'+ direct +'</p>\ 72 <p>主演:'+ mainActor.reduce(function(prev,curv){ 73 prev += curv + " "; 74 return prev; 75 }) +'</p>\ 76 <p>编剧:'+ screenWriter.reduce(function(prev,curv){ 77 prev += curv + " "; 78 return prev; 79 }) +'</p>\ 80 <p>剧情:'+ gut +'</p>\ 81 </div>'; 82 console.log(htmlStr); 83 $(htmlStr).appendTo('body') 84 .css({position:'absolute',left:$(window).outerWidth()/2,bottom:100,width:400,marginLeft:-200,top:505}); 85 } 86 }); 87 }).children() 88 .eq(0).attr('src',ele.poster) 89 .next().text(ele.name); 90 $Wrapper.append($MovieSection); 91 }); 92 } 93 }); 94 }else{ 95 //非vip 96 } 97 } 98 }); 99 </script>
通过上面的【回调地狱】就有一个值得思考的问题了,如何避免这种代码带来的负面影响呢?可以参考另一篇博客:jQuery使用():Deferred有状态的回调列表(含源码)如果要完整的解析整个jQuery.ajax解决这种【回调地狱】的问题就相当于要将jQuery.Deferred的实现机制全部解析一篇,所以这里就不再赘述了。用最简单的描述就是当通过jQuery.ajax()创建一个请求时,jQuery.ajax()会返回一个jQuery.Deferred对象,更准确的说是会返回Deferred.promise对象,这样就可以通过在外部接收这个对象,promise对象上包含了一系列的异步状态的回调函数的注册方法done、fail、progress、then。这些方法的具体使用参考前面那篇博客,下面我通过then方法来改造上面那段【回调地狱】的代码:
1 $.ajax({ 2 url:'https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/power', 3 type:"POST", 4 data:{ 5 username:"cst", 6 password:"123123" 7 } 8 //请求会员资源--电影列表 9 }).then(function(res){ 10 if(res.data.power == 'root'){ 11 //vip 网络地址发送请求 12 return $.ajax({ 13 url:'https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/movieList', 14 type:'GET' 15 }); 16 } 17 // 18 }).then(function(res){ 19 var data = res.data; 20 var $Wrapper = $('.wrapper'); 21 var df = $.Deferred(); 22 $.each(data,function(index,ele){ 23 // ele.name ele.poste 24 var $MovieSection = $('.tpl').clone().removeClass('tpl').addClass('movieSection'); 25 $MovieSection.data({id:ele.id}) 26 .on('click',function(){ 27 df.resolve($(this)); 28 }) 29 .children() 30 .eq(0).attr('src',ele.poster) 31 .next().text(ele.name); 32 $Wrapper.append($MovieSection); 33 }); 34 return df.promise(); 35 }).then(function(dom){ 36 return $.ajax({ 37 url:"https://easy-mock.com/mock/5c09f40d3c098813c612cce6/movie/movieInfo", 38 type:'GET', 39 data:{ 40 movieId:dom.data('id') 41 } 42 }) 43 }).then(function(res){ 44 console.log(res); 45 var data = res.data; 46 var direct = data.direct; 47 var gut = data.gut; 48 var mainActor = data.mainActor; 49 var screenWriter = data.screenwriter; 50 var htmlStr = '<div class="mask">\ 51 <p>导演:'+ direct +'</p>\ 52 <p>主演:'+ mainActor.reduce(function(prev,curv){ 53 prev += curv + " "; 54 return prev; 55 }) +'</p>\ 56 <p>编剧:'+ screenWriter.reduce(function(prev,curv){ 57 prev += curv + " "; 58 return prev; 59 }) +'</p>\ 60 <p>剧情:'+ gut +'</p>\ 61 </div>'; 62 console.log(htmlStr); 63 $(htmlStr).appendTo('body') 64 .css({position:'absolute',left:$(window).outerWidth()/2,bottom:100,width:400,marginLeft:-200,top:505}); 65 });
上面改造后的代码也就是开发中需要遵循的单一职责原则。