【黑马】Vue全家桶-前后端交互(学习打卡05)
之前我们都是用的假数据,真实开发中需要使用从后台拿到的接口数据。
整体学习目标:
- 说出什么是前后端交互模式
- 说出 Promise 的相关概念和用法(处理异步的调用)
- 使用 fetch 进行接口调用
- 使用 axios 进行接口调用
- 使用 async/await 方式调用接口
- 基于后台接口实现案例
【前后端交互】(P75~99)
1.前后端交互模式
1.1 接口调用方式
- 原生ajax
- 基于jQuery的ajax
- fetch
- axios
1.2 URL地址格式
传统的URL
- 格式:
schema://host:port/path?query#fragment
- 含义如下(前三项必须,后几项可选):
schema
:协议。例如http、https、ftp等host
:域名或者IP地址port
:端口,http默认端口80,可以省略path
:路径,例如/abc/a/b/cquery
:查询参数,例如 uname=lisi&age=12fragment
:锚点(哈希Hash),用于定位页面的某个位置
- 格式:
Rastful形式的URL
- HTTP请求方式
- GET 查询
- POST 添加
- PUT 修改
- DELETE 删除
- HTTP请求方式
客户端需要通过url地址去发送请求,然后服务器会根据不同的url地址返回不同的数据,数据的格式就是json
2.Promise用法
是ES6引入的新语法,专门用来处理异步编程(和之前用到的Ajax类似)
2.1 异步调用
JavaScript的执行环境是「单线程」。所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程
异步模式可以一起执行多个任务
JS中常见的异步调用
- 定时任务
- ajax
- 事件函数
多次异步调用的依赖分析
- 多次异步调用的结果顺序不确定
- 异步结果如果存在依赖(先后顺序),需要嵌套(多层嵌套会影响代码可读性)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18$.ajax({
url: 'http://localhost:3000/data',
success: function(data) {
console.log(data)
$.ajax({
url: 'http://localhost:3000/data1',
success: function(data) {
console.log(data)
$.ajax({
url: 'http://localhost:3000/data2',
success: function(data) {
console.log(data)
}
});
}
});
}
});
2.2 Promise概述
Promise 是异步编程的一种解决方案,从语法上讲,Promise是一个对象(也是一个构造函数),从它可以获取异步操作的消息。
- 主要解决异步深层嵌套的问题(防止形成“回调地狱”)
- Promise 提供了简洁的API,使得异步操作更加容易
2.3 Promise基本用法
从语法上看,它是一个对象,也是一个函数
- 实例化
Promise
对象,构造函数中传递参数,该函数中用于处理异步任务 resolve
和reject
两个参数用于处理成功和失败的两种情况,并通过p.then
获取处理结果- 语法模板:
1
2
3
4
5
6
7
8
9
10
11var p = new Promise(function(resolve, reject){
// 成功时调用 resolve();
// 失败时调用 reject();
});
//获取处理结果
p.then(function(ret){
// 从resolve得到正常结果
},function(info){
// 从reject得到错误信息
});
简单案例:
1 |
|
它实际上就是把我们之前用到的回调函数用.then
的方式给重构了,这样的话代码就不会有多层嵌套了,而是变成了线性的结构。
2.4 基于Promise发送Ajax请求
处理原生Ajax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function queryData(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState != 4) return;
if(xhr.status == 200) {
resolve(xhr.responseText);
}else{
reject('出错了');
}
};
xhr.open('get', '/data');
xhr.send(null);
});
}基于Promise发送Ajax请求并解决回调地狱问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- 基于Promise发送Ajax请求 -->
<script type="text/javascript">
// 封装一个独立的函数
function queryData(url) {
// 产生一个Promise实例对象
var p = new Promise(function(resolve, reject){
// 提供一个XML实例对象
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);
});
// 返回实例对象
return p;
}
// queryData('http://localhost:3000/data')
// .then(function(data){
// console.log(data);
// },function(info){
// console.log(info)
// });
// ============================
// 发送多个ajax请求并且保证顺序
queryData('http://localhost:3000/data')
.then(function(data){
console.log(data)
return queryData('http://localhost:3000/data1');
})
.then(function(data){
console.log(data);
return queryData('http://localhost:3000/data2');
})
.then(function(data){
console.log(data)
});
</script>
</body>
</html>
多个任务之间通过.then
的方式变成线性的关系,这样就保证了他们执行的顺序。每个任务return
出来的都是新Promise实例对象,下一个.then
调用的就是它上边return
出来的。另外,.then()
函数中的参数data用于接收上一个异步任务的处理结果。
2.5 then参数中的函数返回值
- 有两种情况:
- 返回 Promise 实例对象
- 返回的该实例对象会调用下一个then
- 返回普通值
- 返回的普通值会直接传递给下一个then,通过then参数中函数的参数接受改值
- 返回 Promise 实例对象
2.6 Promise常用的API
(1)实例方法
.then()
- 得到异步任务正确的结果
.catch()
- 获取异常信息
.finally()
- 成功与否都会执行(不是正式标准)
1 |
|
(2)对象方法
all()和race()都属于Promise的对象方法,
刚刚的then、catch、finally都是Promise原型对象(prototype)中的实例方法。
.all()
并发处理多个异步任务,所有的任务完成才能得到结果。
Promise.all
方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve
转换为一个promise)。它的状态由这三个promise实例决定
.race()
并发处理多个异步任务,只要有一个任务完成就能得到结果。
Promise.race
方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled
或rejected
),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数
1 |
|
3.接口调用-fetch用法
- 比传统Ajax更加简单,功能也更加强大,更灵活,可看做是xhr(传统Ajax)的升级版。
- 基于Promise实现
官方说明:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
语法结构如下:
1 | fetch(url).then(fn2) |
Fetch API基本使用
1 |
|
Fetch API参数传递
常用配置选项
- method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)
- body(String):HTTP的请求参数
- headers(Object):HTTP的请求头,默认为{}
GET请求方式的参数传递
- 传统的URL,通过问号传递参数
1
2
3
4
5
6fetch('/abc?id=123').then(data=>{
return data.text();
}).then(ret=>{
// 注意这里得到的才是最终的数据
console.log(ret)
}); - restful形式的URL,通过斜杠传递参数
1
2
3
4
5
6
7
8
9fetch('/abc/123', {
method: 'get'
})
.then(data=>{
return data.text();
}).then(ret=>{
// 注意这里得到的才是最终的数据
console.log(ret)
});
- 传统的URL,通过问号传递参数
DELETE请求方式的参数传递,通过斜杠传递参数
1
2
3
4
5
6
7
8
9fetch('/abc/123', {
method: 'delete'
})
.then(data=>{
return data.text();
}).then(ret=>{
// 注意这里得到的才是最终的数据
console.log(ret)
});POST请求方式的参数传递(第一种用法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14fetch('/books', {
method: 'post',
// body用来传递实际的数据
body: 'uname=lisi&pwd=123',
// headers请求头也是必须设置的,用来指定一下请求的内容类型
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(data=>{
return data.text();
}).then(ret=>{
console.log(ret)
});POST请求方式的参数传递(第二种用法:设置成json格式的post请求)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16fetch('/books', {
method: 'post',
// body用来传递实际的数据
body: JSON.stringify({
uname: 'lisi',
age: 12
// headers请求头也是必须设置的,用来指定一下请求的内容类型
headers: {
'Content-Type': 'application/json'
}
})
.then(data=>{
return data.text();
}).then(ret=>{
console.log(ret)
});PUT请求方式的参数传递
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15fetch('/books/123', {
method: 'put',
body: JSON.stringify({
uname: '张三',
pwd: '789'
})
headers: {
'Content-Type': 'application/json',
}
}).then(data=>{
return data.text();
}).then(ret=>{
// 注意这里得到的才是最终的数据
console.log(ret)
});
完整案例:
1 |
|
Fetch API响应结果的数据格式
- text():将返回体处理成字符串类型
- json():返回结果和JSON.parse(responseText)一样
1 | fetch('/abc' then(data=>){ |
1 |
|
4.接口调用-axios用法
axios基本特性
它是专门的第三方的JS库,相比来说要比fetchAPI更加强大。
官网:https://github.com/axios/axios
- 基于promise用于浏览器和node.js的http客户端
- 支持浏览器和node.js
- 支持promise
- 能拦截请求和响应
- 自动转换JSON数据
- 能转换请求和响应数据
axios基本使用
- 基本用法
1
2
3
4
5axios.get('/adata')
.then(ret=>{
// 注意data属性是固定的用法,用于获取后台的实际数据
console.log(ret.data)
})
1 |
|
axios的常用API
- get: 查询数据
- post: 添加数据
- put: 修改数据
- delete: 删除数据
axios的参数传递
GET传递参数
- 通过 URL 以问号形式传递参数通过 URL 以restful斜杠形式传递参数
1
2
3
4axios.get('/adata?id=123')
.then(ret=>{
console.log(ret.data)
})1
2
3
4axios.get('/adata/123')
.then(ret=>{
console.log(ret.data)
}) - 通过 params 选项传递参数
1
2
3
4
5
6
7
8axios.get('/adata',{
params: {
id: 123
}
})
.then(ret=>{
console.log(ret.data)
})
- 通过 URL 以问号形式传递参数
DELETE传递参数(与GET类似)
- 通过 URL 以问号形式传递参数通过 URL 以restful斜杠形式传递参数
1
2
3
4axios.delete('/adata?id=123')
.then(ret=>{
console.log(ret.data)
})1
2
3
4axios.delete('/adata/123')
.then(ret=>{
console.log(ret.data)
}) - 通过 params 选项传递参数
1
2
3
4
5
6
7
8axios.delete('/adata',{
params: {
id: 123
}
})
.then(ret=>{
console.log(ret.data)
})
- 通过 URL 以问号形式传递参数
POST传递参数
- 通过选项传递参数(默认传递的是json格式的数据)
1
2
3
4
5
6axios.post('/axios', {
uname: 'Tom',
pwd: 123
}).then(ret=>{
console.log(ret.data)
}) - 通过 URLSearchParams 传递参数(application/x-www-form-urlencoded)
1
2
3
4
5
6const params = new URLSearchParams();
params.append('uname', 'zhangsan');
params.append('pwd', '111');
axios.post('/api/test', params).then(ret=>{
console.log(ret.data)
})
- 通过选项传递参数(默认传递的是json格式的数据)
PUT传递参数(与POST类似)
- 通过选项传递参数(默认传递的是json格式的数据)
1
2
3
4
5
6axios.put('/axios/123', {
uname: 'Tom',
pwd: 123
}).then(ret=>{
console.log(ret.data)
}) - 通过 URLSearchParams 传递参数(application/x-www-form-urlencoded)
1
2
3
4
5
6const params = new URLSearchParams();
params.append('uname', 'zhangsan');
params.append('pwd', '111');
axios.put('/api/test', params).then(ret=>{
console.log(ret.data)
})
- 通过选项传递参数(默认传递的是json格式的数据)
总结:
- get和 delete请求传递参数
- 通过传统的url 以 ? 的形式传递参数
- restful 形式传递参数
- 通过params 形式传递参数
- post 和 put 请求传递参数
- 通过选项传递参数
- 通过 URLSearchParams 传递参数
- get和 delete请求传递参数
axios的响应结果
响应结果的主要属性:
- data: 实际响应回来的数据
- headers: 响应头信息
- status: 响应状态码
- statusText: 响应状态信息
1 | axios.get('http://localhost:3000/axios-json').then(function(ret){ |
axios的全局配置
axios.defaults.timeout = 3000;
//超过时间axios.defaults.baseURL = 'http://localhost:3000/app';
//默认地址(基准请求地址)axios.defaults.headers[ 'mytoken' ] = 'aqwerqwer2ewrwe23eresdf23'
//设置请求头
1 | // 配置请求的基准URL地址 |
axios拦截器用法
- 请求拦截器
- 请求拦截器的作用是在请求发送前进行一些操作
- 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
1
2
3
4
5
6
7
8
9
10
11// 添加一个请求拦截器
axios.interceptors.request.use(function(config) {
// console.log(config.url)
// 1.1 任何请求都会经过这一步,在发送请求之前做些什么,进行一些信息设置
config.headers.mytoken = 'nihao';
// 1.2 这里一定要return 否则配置不成功
return config;
}, function(err){
// 1.3 对请求错误做点什么,处理响应的错误信息
// console.log(err)
})
- 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
- 请求拦截器的作用是在请求发送前进行一些操作
- 响应拦截器
- 响应拦截器的作用是在接收到响应后进行一些操作
- 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
1
2
3
4
5
6
7
8axios.interceptors.response.use(function(res) {
// 2.1 在接收响应做些什么
var data = res.data;
return data;
}, function(err){
// 2.2 对响应错误做点什么
console.log(err)
})
- 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
- 响应拦截器的作用是在接收到响应后进行一些操作
5.接口调用-async/await用法
async/await基本用法
- async/await是ES7引入的新语法,可以更加方便地进行异步操作
- async作为一个关键字放到函数前面
- 任何一个
async
函数都会隐式返回一个promise
(async函数的返回值是Promise实例对象)
- 任何一个
await
关键字只能在使用async
定义的函数中使用,不能单独使用- await后面可以直接跟一个Promise实例对象(await可以得到异步的结果)
- async/await 让异步代码看起来、表现起来更像同步代码
1 | async function queryDate(id) { |
1 |
|
async/await处理多个异步请求
多个异步请求的场景:
1 | async function queryDate(id) { |
1 |
|
6.基于接口的案例
- 图书相关的操作基于后台接口数据进行操作
- 需要调用接口的功能点
功能点 请求方式 URL 地址 图书列表数据加载 GET http://localhost:3000/books 添加图书 POST http://localhost:3000/books 验证图书名称是否存在 GET http://localhost:3000/books/book/:name 编辑图书-根据 ID 查询图书信息 GET http://localhost:3000/books/:id 编辑图书-提交图书信息 PUT http://localhost:3000/books/:id 删除图书 DELETE http://localhost:3000/books/:id
特别感谢: