一,前言
Axios 不必多介绍了。
在项目中,我们并不会直接使用 Axios,而是会对它进行一层封装。
这里提供两种不同的风格,有简单的,也有相对复杂的
二,正文
一,第一种
request.js
import axios from 'axios'
// 创建axios实例。统一配置
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 15000 // 请求超时时间
// .... 其他信息
})
// request拦截器
service.interceptors.request.use(config => {
//... 获取token,存储token 等操作
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// respone拦截器
service.interceptors.response.use(
response => {
// ....
return response.data
},
error => {
// ....
return Promise.reject(error)
}
)
export default service
请求方法
import request from '@/utils/request'
//request() 返回的是一个 Promise
export function login(username, password) {
return request({
url: '/admin/login',
method: 'post',
//withCredentials: true, //跨域允许携带cookie
//timeout: 30000,
//headers: { 'Content-Type': 'application/json', 'request-ajax': true },
data: {
username,
password
}
})
使用(也是两种使用风格)
import {
login } from '@/api/login'
confirm(){
login(this.loginForm).then(response => {
//...
}).catch( error => {
//...
})
}
//使用async await 语法糖
async confirm(){
try{
const response = await login(this.loginForm)
// ...
}catch(error){
// ....
}
}
二,第二种
request.js
import axios from 'axios'
//响应拦截器
axios.interceptors.response.use(
function(response) {
//....
return response
},
function(error) {
return Promise.reject(error)
}
)
//请求拦截器
axios.interceptors.request.use(
function(config) {
//...
return config
},
function(error) {
return Promise.reject(error)
}
)
/*
* 封装请求方法
*/
const request = function(query) {
return axios
.request(query)
.then((res) => {
//...
if (res.data.code === 401) {
vue.prototype.$$router.push({
path: '/login' })
return Promise.reject(res.data)
} else if (res.data.code === 500) {
return Promise.reject(res.data)
} else if (res.data.code === 501) {
return Promise.reject(res.data)
} else if (res.data.code === 502) {
vue.prototype.$$router.push({
path: '/login' })
return Promise.reject(res.data)
} else {
return Promise.resolve(res.data)
}
})
//对错误进行处理
.catch((e) => {
return Promise.reject(e.message)
})
}
//post请求 ----> json格式的post请求
const post = function(url, params) {
const query = {
url: url,
method: 'post',
withCredentials: true, //跨域允许携带cookie
timeout: 30000,
data: params,
headers: {
'Content-Type': 'application/json', 'request-ajax': true },
}
return request(query)
}
//Get请求
const get = function(url, params) {
const query = {
url: url,
method: 'get',
withCredentials: true,
timeout: 30000,
params: params,
headers: {
'request-ajax': true },
}
return request(query)
}
//post请求
const form = function(url, params) {
const query = {
url: url,
method: 'post',
withCredentials: true,
timeout: 30000,
data: params,
headers: {
'Content-Type': 'multipart/form-data',
'request-ajax': true,
},
}
return request(query)
}
请求方法
import {
post } from '@/util/request'
//默认导出的是一个对象
export default {
login: query => post(`/api/login`, query),
logout: query => post(`/api/logout`, query)
}
在 vue.config.js 配置一下代理
module.exports = {
devServer: {
open: true,
host: 'localhost',
port: 8001,
https: false,
hotOnly: false,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
},
},
},
}
使用
import loginApi from '@/api/login'
handleLogin() {
loginApi
.login(this.loginForm)
.then((result) => {
})
//其实一般不捕获这个异常 要结合后端返回数据的情况
.catch((error) => console.log(error))
//使用async await 语法糖
async handleLogin(){
try{
const response = await loginApi.login(this.loginForm)
// ...
}catch(error){
//其实一般不捕获这个异常。要结合后端返回数据的情况
// ....
}
}
其实这两种风格大同小异,主要是想利用这个来更加熟悉 Promise
三,Promise
1,简介
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。它最早由社区提出并实现,ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。
JS 基础:JS异步任务会在异步任务队列中,只有执行完主任务(主进程),才会不断轮询异步任务队列然后执行队列中的方法。JS异步任务有:文件的加载,定时器,表单请求,ajax请求…
2,Promise的三种状态
- Pending状态(进行中)
- Fulfilled状态(已成功)
- Rejected状态(已失败
Promise 的状态一旦发生改变就不再变化,不可逆(两种状态改变:成功或失败)
- Pending -> Fulfilled
- Pending -> Rejected
3,语法
(1) 进行阶段
console.log(new Promise((resolve,reject) => {
})) //pending
(2) 如何改变状态
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve作用是将Promise对象状态由“未完成”变为“成功”,也就是Pending -> Fulfilled,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;而reject函数则是将Promise对象状态由“未完成”变为“失败”,也就是Pending -> Rejected,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
//成功后用resolve方法来通知(改变Promise的状态)
new Promise((resolve,reject) => {
resolve("成功状态")
})
new Promise((resolve,reject) => {
reject("拒绝状态")
})
(3) 状态改变后的回调
then:Promise实例生成后,可用then方法分别指定两种状态回调参数。then 方法可以接受两个回调函数作为参数:
- Promise对象状态改为Resolved时调用 (必选)
- Promise对象状态改为Rejected时调用 (可选)
new Promise((resolve,reject) => {
// reject("拒绝状态") //失败的 ---> (干活的)
resolve("成功状态") //成功的 ---> (干活的)
}).then(value => {
console.log(value) //成功会执行这个 ---> (干完活对数据的处理) --- value 是 resolve传过来的数据
},reason => {
console.log(reason) //失败会执行这个 ---> (干完活对数据的处理) --- reason 是 reject传过来的数据
})
//成功状态
提示:
- 如果没有改变Promise的状态,then就永远无法执行
- 每个then返回的也是一个Promise,而且默认是返回成功的结果
new Promise( (resolve,reject) => {
resolve()
})
.then(msg => {
},error => {
})
.then(msg => {
},error => {
})
//其实就等价于:
new Promise( (resolve,reject) => {
resolve()
})
.then( () => {
return new Promise( (resolve,reject) => {
resolve()
})
})
.then(msg => {
},error => {
})
- 如果then里面有返回值,那么下一个then的参数就是返回值内容(即在下一个then就能接收到)
let p1 = new Promise((resolve,reject) => {
resolve("resolve")
})
.then(
value => {
return "返回值"},
reason => {
console.log(reason) })
.then(
value => {
console.log(value)} //结果:返回值,
reason => {
console.log(reason) })
- 如果返回的对象中有一个 then方法,那么会被封装为Promise
let p1 = new Promise((resolve,reject) => {
resolve("resolve")
})
.then(
value => {
return {
then((resolve,reject) => {
resolve("resolve")
})
}},
reason => {
console.log(reason) })
- 一般是这样使用的。不是直接使用Promise,而是封装成一个函数,需要的时候调用
function request(){
return new Promise((resolve,reject) => {
//异步调用,请求后端接口
resolve(data)
})
}
request().then(value => {
console.log(value)
})
(4)执行顺序
let promise = new Promise(function(resolve, reject){
console.log("AAA");
resolve()
});
promise.then(() => console.log("BBB"));
console.log("CCC")
// AAA
// CCC
// BBB
执行后,我们发现输出顺序总是 AAA -> CCC -> BBB。表明,在Promise新建后会立即执行,所以首先输出 AAA。然后,then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行,所以BBB 最后输出。
(5)Promise多种错误检测与catch使用
let p1 = new Promise((resolve,reject) => {
reject("resolve") //这样会进入reject
throw new Error() //这样也会进入reject
hd + 1 //hd变量没定义,报错,也会进入reject
})
.then(
value => {
console.log(value) },
reason => {
console.log(reason) })
//可以使用catch捕获,对错误统一进行处理
let p1 = new Promise((resolve,reject) => {
reject("resolve") //这样会进入reject
throw new Error() //这样也会进入reject
hd + 1 //hd变量没定义,报错,也会进入reject
})
.then( value => {
console.log(value) })
.then( value => {
console.log(value) })
.then( value => {
console.log(value) },reason => {
console.log(reason) })
.catch( reason => {
console.log(reason) //一般习惯放在最后,对所有Promise统一处理
})
let p1 = new Promise((resolve,reject) => {
reject("resolve") //这样会进入reject
throw new Error() //这样也会进入reject
hd + 1 //hd变量没定义,报错,也会进入reject
})
.then( value => {
console.log(value) },reason => {
console.log(reason) })
.catch( reason => {
console.log(reason) //一般习惯放在最后,对所有Promise统一处理
})
.finally(() => {
console.log("始终会执行")
})
(6)Promise.all 批量获取数据
const p1 = new Promise((resolve,reject) => {
resolve("第一个异步")
})
const p2 = new Promise((resolve,reject) => {
resolve("第二个异步")
})
Promise.all([p1,p2]).then(result => {
console.log("all") //全部成功才是成功
})
.catch(() => {
console.log("error") //catch也是返回一个Promise,状态也是成功
})
(7)Promise 语法糖:async await
async
顾名思义,异步。async函数对 Generator 函数的改进,async 函数必定返回 Promise(async就类似于 Promise,而且是成功的状态)
,我们把所有返回 Promise 的函数都可以认为是异步函数。特点体现在以下四点:
- 内置执行器
- 更好的语义
- 更广的适用性
- 返回值是 Promise
await
顾名思义,等待。正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,ms);
})
}
async function handle(){
console.log("AAA")
await sleep(5000)
console.log("BBB")
}
handle();
//handle().then( msg => {},error => {} )
// AAA
// BBB (5000ms后)
我们定义函数sleep,返回一个Promise。然后在handle函数前加上async关键词,这样就定义了一个async函数。在该函数中,利用await来等待一个Promise。
(8)async await 语法糖的错误处理
async function hd(){
console.log(name)
}
hd().catch( error => console.log(error) )
//标准
async function hd(){
try{
let data = await ajax()
}catch(error){
}
}