案例代码:
set(){
this.$refs.addCate.validate(async (valid) => {
console.log('数据提交请求');
if (!valid){ return 'shibai'}
await this.addCateList(this.ruleForm)
await this.$refs.addCate.resetFields();
this.visible=false
});
}
其中的addCateList函数封装如下(addCateList函数是封装在vuex仓库actions中的函数,封装目的是为了践行模块化封装的思想,其中的cateAddreq是一个在user.js中封装的,用于发送axios请求的axios方法,user.js是一个专门封装发axios请求的文件,此处未写出来)
async addCateList(context, da) {
const { data } = await cateAddreq(da);
if (data.code === 1) {
return this.$message.error("此分类已存在");
}
if (data.code !== 0) {
return this.$message.error("请求错误");
}
context.dispatch("getCateList");
},
需要知道的知识点:
1.async是返回一个Promise对象 ,然后await是接收一个异步请求的返回结果,让其通过async标记下的Promise对象调用Promise.solve()方法,将await标记的语句之后的代码以异步微任务挂载,实现当前行代码相对而言同步执行的效果
2.浏览器解析引擎会先执行同步代码,再执行异步代码;在异步代码的函数内部也是会先执行其内的同步代码,再执行其中的异步代码, 原理上来说,不管嵌套多少层,在一个单独的作用域中,先同步后异步是不变的规则
分析:
addCateList()中的代码分析
在该函数中,存在如下同步代码
- if (data.code === 1) {return this. $ message.error(“此分类已存在”)}
- if(data.code !==0){return this.$message.error(“请求错误”)}
存在如下异步代码: - const { data } = await cateAddreq(this.ruleForm)
- context.dispatch(“getCateList”)
步骤:
1.首先通过cateAddreq()发起axios请求,将数据发送到服务端
2.通过if()语句判断服务器返回的状态码,如果状态码等于1,则表示分类已经存在,并提示用户,如果状态码在排除等于1之后,还是不等于0,则提示用户请求错误
3.通过Mutations中定义的getCateList方法来重新请求并更新数据,依托vue数据模型控制视图的原理渲染更新页面
问题分析
在整个过程中,由于浏览器解析引擎先执行同步代码,所以会导致第二步中的if语句会先执行,造成的结果是会由于data还在异步中未生成而导致data.code不存在,从而报错
问题解决:
此时使用async来标记addCateList()函数,并用await对异步的函数cateAddreq()进行标记,让其可以在if语句之前同步执行
set()函数中代码分析
在该回调函数中,存在如下同步请求:
- if (!valid){ return ‘shibai’}
- this.visible=false
存在如下异步请求:
- this.addCateList(this.ruleForm)
- this.$refs.addCate.resetFields() //此函数是elementUi中,用于重置表单的方法
在set()函数中,只有一个主体执行函数,就是this.$refs.addCate.validate()这个方法(这是elementUi中关于提交表单时,对表单进行二次预检的方法),其内存在一个回调函数。
代码要实现的需求如下:
1.在点击表单提交按钮后,对表单进行预检,如果不通过,则直接return返回
2.如果预检通过,则发送请求,向服务器提交表单数据
3.发送请求之后,将表单清空
4.将表单关闭
问题分析
整个过程中,由于浏览器解析引擎执行方式为先同步后异步,就会导致第四步的的表单关闭在第一步预检之后就直接执行了,造成的结果是第二步中无法获取到数据,并且第三步中要清空表单时也会由于无法获取到表单元素而无法完成。
问题解决
此时使用async来标记validate()里面的回调函数,并用await对异步的函数this.addCateList()
和this.$refs.addCate.resetFields()进行标记,让其可以在表单关闭语句之前同步执行,解决表单提前关闭导致的一系列问题
总结
async /await 的使用场景:
在一段需要严格按顺序执行生效,但却又有同步和异步代码穿插在一起的情况下,需要使用async / await来控制代码的执行顺序
另附
以上代码在总体的同步异步流程上并没有问题,但是由于模块之间互相导入引用也会需要一定的加载时间,这样就会导致有一定的几率在执行到set()中第一个await时,
由于过长的引入路径而使得this.addCateList()未被识别到的情况。会出现报错。
解决办法就是如下,将代码直接整合在当前执行的.vue文件中
set(){
this.$refs.addCate.validate(async (valid) =>
{
if (!valid){ return 'shibai'}
const { data } = await cateAddreq(this.ruleForm)
if (data.code === 1) {
return this.$message.error("此分类已存在");
}
if(data.code !==0){return this.$message.error("请求错误")}
this.$store.dispatch('artCategory/getCateList') //页面渲染不需要严格的同步执行,只需要在请求发送之后执行即可 ,所以不使用await标记
await this.$refs.addCate.resetFields()
this.visible=false
});
},