这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
今天本来准备继续更新PageHelper源码解读系列文章,奈何笔记本不再身边,今天说点别的内容:前段的异步同步问题,先来说说Promise吧。
vue项目中常见的api请求方式
熟悉vue的小伙伴一定不会对vue-element-admin感到陌生,这个框架页基本是若依管理系统ruoyi-ui部分的基础框架,我们对到底是谁先按照这种前端规范模式来写的也不太感兴趣。
如果真正的使用过vue-element-ui或者若依系统的小伙伴页一定不会对其中的API请求方式感到陌生,其请求方式大致如下:封装axios.requst,在src/api文件夹下按照如下方式执行:
import request from '../utils/request';
// post方法
export function post_api(query) => {
return request({
path: '/api-url',
method: 'post',
data
})
}
// get方法
export function get_api(query) {
return request({
url: '/api-url',
method: 'get',
params: query
})
}
这里返回的request(xxx)是个什么呢?
Promise
答案是一个Promise。那么Promise是什么呢?
可以简单理解为目前Javascript实现异步编程的强大工具。
Promise有三种状态:Pending(进行中)/ Fulfilled(已成功)/ Rejected(已失败),如下面代码所示:
// 代码A
new Promise((resolve, reject) => {
if(xx) {
resolve(xxxx)
} else {
reject(new Error("xxx"))
}
})
// 代码B
这段代码首先会执行代码A,然后执行new Promiseb部分,不管promise的状态如何,也会立即执行代码B部分代码。
那么如何让Promise部分代码执行完毕后再执行B代码呢?按照下面这样写:
// 代码A
new Promise((resolve, reject) => {
if(xx) {
resolve(xxxx)
} else {
reject(new Error("xxx"))
}
}).then(() => {
// 代码B
}).catch(() => {
// 代码C
}).finally(() => {
// 代码D
})
这段代码表示若Promise部分以resolve后返回,即“已成功”,这执行then部分代码;若“已失败”返回则执行catch部分代码;而且无论成功与失败,finally部分代码总要执行。
一种生产环境中使用finally的场景是,某些后台接口可能成功,也可能会因为超时的情况发生失败,这种情况下,一些统一的请求后处理需要放在finally部分,例如将loading状态改为false等。
this.loading = true
api.request(...)
.then(...)
.catch(...)
.finally(() => {
this.loading = false
})
题外话
Javascript中还有两个异步同步的关键字,await/async,有过java编程经验的小伙伴应该不会感到陌生。这两个关键字也是为Promise服务的。async用来修饰function,await用于在async修改的function内部使用,两者互相关联使用才会生效。
使用async声明的function返回的总是一个promise。即如果一个函数使用async修饰,我们便不能再使用常规方式获取其返回值,而是需要像Promise一样取值,例如:
async demo() {
return "哈哈"
}
demo().then(val => {
console.log(val) // 哈哈
})
而await,顾名思义,等待Promise的执行结束。
例如:在MDN上的一个例子:
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();