前端框架Vue:fetch、axios、async、await等在前后端数据交互中的应用

Vue全家桶-前后端交互

一、什么是前后端交互模式

1、接口调用方式

  • 原生ajax
  • 基于Jquery的ajax
  • fetch
  • axios

二、Promise的概念和用法

1、异步调用

异步效果分析

  • 定时任务
  • Ajax
  • 事件函数

多次异步调用的依赖分析

  • 多次异步调用的结果顺序不确定
  • 异步调用结果如果存在依赖关系的话需要嵌套(回调地狱)

2、Promise概述

Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息(解决回调地狱)

使用Promise主要的好处

  • 可以避免多层异步调用嵌套问题(回调地狱)
  • Promise对象提供了简洁的API,使得控制异步操作更加容易

3、Promise基本用法

  • 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务
  • resolve和reject两个参数用于处理成功和失败两种情况,并通过获取处理结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbUCb5d8-1607008749313)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201205327603.png)]

<script type="text/javascript">
			/**
			 * Promise基本使用
			 */
			var p = new Promise(function(resolve,reject){
				//这里用于实现异步任务(Ajax)
				setTimeout(function(){
					var flag = false;
					if(flag){
						//正常情况
						resolve('hello');
					}else{
						//异常情况
						reject('error');
					}
				},100)
			});
			
			p.then(function(data){
				console.log(data);
			},function(info){
				console.log(info)
			});
			
		</script>

4、then参数中的函数返回值

  • 返回Promise实例对象

返回的该实例对象会调用下一个then

  • 返回普通值

返回的普通值会直接传递给下一个then,通过then参数中函数的参数接受该值

<script type="text/javascript">
    /*
      then参数中的函数返回值
    */
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }
    queryData('http://localhost:3000/data')
      .then(function(data){
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        return new Promise(function(resolve, reject){
          setTimeout(function(){
            //resolve(123);
              reject("error");
          },1000)
        });
      })
      .then(function(data){
        return 'hello';
      })
      .then(function(data){
        console.log(data)
      })

  </script>

Promise常用API

实例方法

  • p.then( ) 得到异步任务的正确结果
  • p.catch( ) 获取异常信息
  • p.finally( ) 成功与否都会执行
<script type="text/javascript">
			/**
			 * Promise常用API-实例方法
			 */
			function foo(){
				return new Promise(function(resolve,reject){
					//定义一个异步定时任务
					setTimeout(function(){
						resolve(123);
					},1000);
				})
			}
			
			foo() //正常
				.then(function(data){
					console.log(data)
				}) //错误
				.catch(function(data){
					console.log(data)
				}) //结束
				.finally(function(){
					console.log("finished") 
				});
			# 这种写法也是ok的
			foo()
				.then(function(data){
					console.log(data)
				},function(data){
					console.log(data)
				})
				.finally(function(){
					console.log("finished")
				})

		</script>

对象方法

  • Promise.all( ) 并发处理多个异步任务,所有任务执行完成才能得到结果
  • Promise.race( ) 并发处理多个任务,只要有一个任务完成就能得到结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hqkNehqR-1607008749316)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201215952979.png)]

注意:这里的result是一个数组,里面的数据跟p1,p2,p3中传递过来的一一对应

<script type="text/javascript">
			/**
			 * Promise常用API-对象方法
			 */
			function queryData(url) {
			      return new Promise(function(resolve, reject){
			        var xhr = new XMLHttpRequest();
			        xhr.onreadystatechange = function(){
			          if(xhr.readyState != 4) return;
			          if(xhr.readyState == 4 && xhr.status == 200) {
			            // 处理正常的情况
			            resolve(xhr.responseText);
			          }else{
			            // 处理异常情况
			            reject('服务器错误');
			          }
			        };
			        xhr.open('get', url);
			        xhr.send(null);
			      });
			    }
			
				var p1 =  queryData('http://localhost:8080/a1'); 
				var p2 =  queryData('http://localhost:8080/a2');
				var p3 =  queryData('http://localhost:8080/a3');
				
				//并发执行(全部执行完才执行)
				Promise.all([p1,p2,p3]).then(function(result){
					console.log(result)
				})
				//(zhiyao)
				Promise.race([p1,p2,p3]).then(function(result){
					console.log(result)
				})
				
				
		</script>

三、fetch的使用

1、fetch概述

更简单的数据获取方式,功能更前大、更灵活,可以看做是xhr的升级版,他还是基于Promise实现的

语法结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x3jPfg5M-1607008749317)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201222623423.png)]

2、基本用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goPuzhbA-1607008749320)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201223356774.png)]

实例

<script type="text/javascript">
			/**
			 * Fetch API基本用法
			 */
			fetch('http://112.74.167.52:8089/channel/createOrder').then(function(data){
				//这里的text()方法属于fetch API一部分,它返回一个Promise对象,用于获取后台返回的数据
				return data.text();
			}).then(function(data){
				console.log(data)
			})
			
</script>

3、fetch请求参数

常用配置选项

  • method(String) ,http请求方式:GET、POST、PUT、DELETE,默认是GET

  • body(String) ,请求体

  • headers(Object) ,请求头的设置

GET方法传递参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrUcopGc-1607008749322)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201224043072.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOHKIUgJ-1607008749323)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201224053741.png)]

POST方法传参

正常开发中,使用application/json格式居多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ypRL1hY-1607008749324)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201225929575.png)]

实例

<script type="text/javascript">
			/**
			 * Fetch 请求参数
			 */
			fetch('http://112.74.167.52:8089/channel/createOrder',{
				method:'post',
				body:JSON.stringify({
					'orderCode':'AS202012010001CN'
				}),
				headers:{
					'Content-Type':'application/json'
				}
			})
			.then(data => {
				return data.text();
			})
			.then(data =>{
				console.log(data);
			})
			
			
		</script>

4、fetch响应结果

响应数据格式

  • text( ):将返回体处理成字符串类型
  • json( ):返回结果和JSON.parse(responseText)一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKleCzVC-1607008749325)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201201230642350.png)]

<script type="text/javascript">
			/**
			 * Fetch 请求参数
			 */
			fetch('http://112.74.167.52:8089/channel/createOrder',{
				method:'post',
				body:JSON.stringify({
					'orderCode':'AS202012010001CN'
				}),
				headers:{
					'Content-Type':'application/json'
				}
			})
			.then(data => {
				//将数据转为json格式
				//return data.text();
				return data.json();
			})
			.then(ret =>{
				//var json = JONS.parse(ret);
				//console.log(json.msg)
				
				//这样就可以取出具体的值
				console.log(ret.msg);
				console.log(ret.resCode); 
				console.log(ret.obj);
			})
			
			
		</script>

四、axios的使用

axios是一个基于Promise用于浏览器和node.js的和HTTP客户端

1、基本特性

  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和响应
  • 自动转换JSON数据

2、axios的基本用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMZDC9DW-1607008749326)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203202055187.png)]

简单示例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/axios.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		
		
		<script type="text/javascript">
			/**
			 * axios的基本使用
			 * 发送get请求
			 */
			axios.get('http://112.74.167.52:8089/channel/get').then(ret => {
				//这里的data是axios的固定属性,用于获取后台返回的实际数据
				console.log(ret.data); 
			})
		</script>
	</body>
</html>

3、axios的常用API

  • get
  • post
  • put
  • delete

get传递参数

  • 通过url传递参数
  • 通过params选项传递参数
//拼接的方式
axios.get('http://112.74.167.52:8089/channel/get?id=1').then(ret => {
				//这里的data是axios的固定属性,用于获取后台返回的实际数据
				console.log(ret.data); 
			})
//restful形式的请求
axios.get('http://112.74.167.52:8089/channel/get/1').then(ret => {
				//这里的data是axios的固定属性,用于获取后台返回的实际数据
				console.log(ret.data); 
			})
// 带对象的参数:params
axios.get('http://112.74.167.52:8089/channel/get',{
				params:{
					id:123,
					name:'pihao'
				}
			}).then(ret => {  
				console.log(ret.data);
			})

post请求传递参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bk6qmafg-1607008749327)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203212936852.png)]

post请求,传递json格式的数据

/**
 * axios
 * post请求,请求体为对象 json格式的数据
 */
axios.post('http://112.74.167.52:8089/channel/createOrder',{
    orderCode:'AS202012030001CN'
}).then(ret => { 
    console.log(ret.data);
})

post请求,表单格式的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zkfb7n2v-1607008749328)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203213648491.png)]

4、axios的响应结果

响应的主要属性

  • data:实际响应回来的数据
  • headers:响应头信息
  • status:响应状态码
  • statusText:响应状态信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5xOK1D2-1607008749329)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203214517099.png)]

5、axios全局配置

  • axios.defaults.timeout = 3000 超时时间
  • axios.defaults.baseURL=‘http://localhost:8080’/app 默认地址
  • axios.defaults.headers[‘token’] = ‘abc123’ 默认请求头

实例

			//url
			axios.defaults.baseURL='http://112.74.167.52:8089/channel/';
			//timeout
			axios.defaults.timeout=3000; 
			//headers
			axios.defaults.headers['mytoken']='hello';
			axios.post('createOrder',{
				orderCode:'AS202012030001CN'
			}).then(ret => { 
				console.log(ret.data);
			})

6、axios拦截器

请求拦截器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zwWfvFzt-1607008749329)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203215455874.png)]

拦截器实例

<script type="text/javascript">
			/**
			 * axios请求拦截器
			 */
			axios.interceptors.request.use(function(config){
				//配置请求头
				config.headers.mytoken = 'pihao';
				//请求的其他配置。。。
				
				//还可以通过config.url获取请求地址,然后对请求地址做相应配置
				
				return config;
			},function(err){
				console.log(err);
			})
			
			//测试请求
			axios.get('http://112.74.167.52:8089/channel/get').then(ret=>{
				console.log(ret.data);
			});
			
		</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mX2xv1Kj-1607008749330)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203220326933.png)]

响应拦截器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpv4Jy0U-1607008749331)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203220500908.png)]

拦截器实例

/**
			 * axios响应拦截器
			 */ 
			axios.interceptors.response.use(function(res){
				//这里的res就是那个还没处理的响应数据
				
				//这里做一个小小的处理
				var data = res.data;
				//直接返回json数据
				return data;
			},function(err){
				console.log(err);
			})
			
			//测试请求
			axios.get('http://112.74.167.52:8089/channel/get').then(ret=>{
				//注意:这里没有 .data
				console.log(ret);
			});

五、async/await方式调用接口

1、async/await的基本用法

  • async/await是ES7引入的新语法,可以更加方便的进行异步操作
  • async关键字用于函数上(async函数的返回值是Promise实例对象)
  • await关键字用于async函数当中(await可以得到异步的结果)

语法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-InMki5pZ-1607008749332)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203221544980.png)]

实例

<script type="text/javascript">
			/**
			 * async/await 处理异步操作
			 */
			axios.defaults.baseURL='http://112.74.167.52:8089/channel/'
			
			//async处理异步任务,返回的其实一个Promise对象,这个对象里面的传的参数的响应的结果
			async function queryData(){
				var res = await axios.get('get');
				return res.data;
			}
			
			//通过then处理Promise
			queryData().then(data => {
				console.log(data); //已经处理过了的json响应数据
			})
		</script>

什么?上个例子懵逼?,那么看看下面这个简历的例子

<script type="text/javascript">
			/**
			 * async/await 处理异步操作
			 */
			async function queryData(){
				var res = await new Promise(function(resolve,reject){
					setInterval(function(){
						resolve('async test');
					},2000);
				})
				return res;
			}
			
			//通过then处理Promise
			queryData().then(data => { 
				console.log(data); //拿到处理的结果 async test
			})
			
		</script>

2、async/await 处理对个异步请求

第一个请求的结果传递给第二个请求的参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vs1bL82T-1607008749333)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201203230528813.png)]

实例

<script type="text/javascript">
			/**
			 * async、await处理多个异步任务
			 */
			axios.defaults.baseURL = 'http://112.74.167.52:8089/channel/';
			
			async function queryData(){
				var info = await axios.get('get');
				//将上个请求的返回值作为参数传递给第二个请求
				var res = await axios.post('createOrder',info.data); 
				return res.data;
			};
			
			queryData().then(res =>{  
				console.log(res);
			}) 
			
			
		</script>

六、基于后台接口实现案例

自己用springboot写的java后台,配合前端vue使用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/axios.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css">
			.grid{
				margin: auto;
				width: 500px;
				text-align: center;
			}
			.grid table{
				width: 100%;
				border-collapse: collapse;
			}
			.grid th,td{
				padding: 10;
				border: 1px dashed orange;
				height: 35px;
				line-height: 35px;
				
			}
			.grid th{
				background-color: orange;
			}
			.grid .book{
				padding-bottom: 10px;
				padding-top: 5px;
				background-color: #F3DCAB;
			}
			.grid .total{
				height: 30px;
				line-height: 30px;
				background-color: hotpink;
			}
		</style>
	</head>
	<body>
		
		<div id="app">
			<div class="grid">
				<div>
					<h1>图书管理</h1>
					<div class="book">
						<div>
							<label for="id">
								编号:
							</label>
							<input type="text" id="id" v-model="id" style="width: 30%" :disabled="flag" v-focus/>
							<label for="name">
								名称:
							</label>
							<input type="text" id="name" v-model="name" style="width: 30%"/>
							<!-- 这里的禁用是为了输入相同的书名的时候,不允许添加 -->
							<button type="button" @click="handel" :disabled="btnFlag">提交</button>
						</div>
						
					</div>
				</div>
				<div class="total">
					<span>总数:{{sum}}</span>
				</div>
				<table >
					<thead>
						<tr>
							<th>编号</th>
							<th>名称</th>
							<th>时间</th>
							<th>操作</th>
						</tr>
					</thead>
					<tbody>
						<tr :key='item.id' v-for='item in books'>
							<td>{{item.id}}</td>
							<td>{{item.name}}</td>
							<td>{{item.date}}</td>
							<td>
								<a href="#" @click.prevent="toEdit(item.id)">修改</a>
								<span>|</span>
								<a href="#" @click.prevent="deleteBook(item.id)">删除</a>
							</td>
						</tr>
						
					</tbody>
					
				</table>
			</div>
		</div>
		
		<script type="text/javascript">
			//设置axios的基准路径
			axios.defaults.baseURL='http://112.74.167.52:8089/';
			axios.interceptors.response.use(function(res){
				return res.data;
			},function(error){
				console.log(error);
			})
			
			var vm = new Vue({
				el: '#app',
				data:{
					id:'',
					name:'',
					flag:false,
					btnFlag:false,
					books:[]
				},
				computed:{
					sum:function(){
						//计算图书的总数
						return this.books.length;
					}
				},
				methods:{
					handel: async function(){
						//该方法其实可以与编辑图书重用
						if(this.flag){
							//编辑图书
							var res = await axios.put('/books/'+this.id,{
								name : this.name
							});
							
							if(res == 'success'){
								//重新加载列表
								this.queryData();
							}
							this.flag = false;
							
						}else{
							//添加图书
							entity = {
								name:this.name,
								id:this.id
							};
							
							var result = await axios.post('books',entity);
							if(result == 'success'){
								this.queryData();
							}

						}
						this.id = '';
						this.name = '';
					},
					toEdit: async function(id){
						//编辑的时候禁止修改id
						this.flag = true;
						//根据id找到相应的数据
						var book = await axios.get('/books/'+id);
						//找到数据之后填充到页面上
						this.id = book.id;
						this.name = book.name;	
					},
					deleteBook: async function(id){
						//删除图书
						var res = await axios.delete('/books/'+id);
						if(res == 'success'){
							//重新加载数据
							this.queryData();
						}
					},
					//加载图书列表
					queryData:async function(){
						this.books = await axios.get('books');
					}
				},
				filters:{
					format:function(val,pattern){
						if(pattern == 'yyyy-MM-dd'){
							return val.getFullYear()+"-"+(val.getMonth()+1)+"-"+val.getDate();
						}
					}
				},
				directives:{
					focus:{
						inserted:function(el){
							el.focus()
						}
					}
				},
				watch:{
					name:async function(val){
						//验证图书名称是否已经存在
						var result = await axios.get('/books/book?name='+this.name);
						// console.log(result); //true or false
						if(result){
						//图书名称已经存在
							this.btnFlag = true;
						}else{
							this.btnFlag = false;
						}
					}
				},
				
				mounted:function(){
					//该生命周期钩子函数被触发的时候,模板已经可以使用了
					//一般此时用于调用接口获取后台数据,然后把数据填充到模板
					
					// axios.get('books').then(res => {
					// 	this.books = res.data;  
					// })
					
					//上面的方法不够简洁,我们可以在方法中封装函数queryData()
					this.queryData();
				}
			});
		</script>
	</body>
</html>


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值