作为有多年java皮毛式编程经验,python也能写几行的我,接触到javaScript之后居然觉得这是一门无法理解的语言,原因就在于它的异步处理。。我希望它按照我写的顺序执行,可是,它偏有自己的想法,使用console.log打印出来的执行顺序,总是让我无语。。。
以往都是通过.then(),昨天在同事的指导下,再次尝试async/await,居然成功了,而今天独自加班,就遇到了进阶需求,庆幸昨天学会了初阶。记录要点
初阶需求
上一篇自定义对话框组件中,当组件做完保存,需要通过emit通知父组件更新列表。我是这么写的:
onSave(){
this.addUsrs();
this.$emit("accountCreated");
this.dialogVisible = false;
....
}
如你所想,addUsers中是一个后台保存的接口,所以,当父组件收到通知开始更新列表的时候,子组件的保存还正在执行呢,所以,父组件更新了个寂寞。。
修正方式1
.then()方法,将emit放到addUsers.then()中执行,具体可参考之前链式调用的博文,今天说说方法2.
修正方式2
1、将this.addUsers定义成一个async函数,其中使用await设置阻塞
//使用async,表示这是一个可以使用await控制执行顺序的同步函数
async addUsrs(){
//保存前的各种处理。。。。。。
await insertUsers(this.form.people); //阻塞,执行保存结束后,才往下走
this.$emit("accountCreated"); //重点:emit放到async函数里面来。走到这里的时候,上一步addUsers已经返回了
},
2、重点:把emit那一句放到addUsers里面来
只有在async函数内部,await才会等待返回后再执行下一步,如果emit还是像之前那样放置this.addUsers()后面,await是无法实现等待insert返回的。
如果emit那一句还是在onSave中,js的调用顺序大概是这样的:
1、执行onSave
2、执行addUsers,发现时间有点长,不等它,立刻返回
2、执行emit
3、父组件收到emit,开始更新列表。这时候addUsers有没有执行完,完全看运气。
如果emit在addUsers里面,js的调用顺序是这样的:
1、执行onSave
2、执行addUsers,发现时间有点长,不等它,立刻返回
2、执行dialogVisible = false,关闭对话框。
外层的主线执行完了,再看addUsers里面的支线:
2.1 执行insertUsers,发现时间有点长,但是前面有await,阻塞,等待执行完才返回
2.2 insertUsers执行完返回,执行emit
2.3 父组件收到通知,开始更新列表。
前面的序号,我分别用了两个2,不是笔误,表示这两个是同步执行的。可以看到,这里其实我们只是控制了emit一定要在insertUsers返回之后执行,其它的执行顺序,是不受我们控制的。而这个执行顺序,是按照函数的调用结构,层层返回的。我们只能控制某一层内的顺序,跨层的是无法控制的。
进阶需求:阻塞多接口
某页面created里面做初始化,一个数据需要同时使用两个接口的返回值,所以,我必须等两个接口都返回之后再做数据处理。但是,这两个接口之间是没有调用顺序的限制的,如果我使用链式调用虽然能实现功能,但是会影响效率。想到以前曾经听某项目在同事分析接口执行顺序的时候,提到过类似于接口1,接口2并发执行,返回后接口3和4顺序执行的说法。。于是,查了一下,果然有个阻塞多接口的方法:Promise.all()
方法1:await
async initProjectInfo(){
const [fetch1Res,fetch2Res] = await Promise.all([fetchData1(this.projectFrm.unid),fetchData2(this.projectFrm.unid)]);
//分别使用fetch1Res和fetch2Res进行数据处理
.....
}
方法2:then
initProjectInfo(){
Promise.all([fetchData1(this.projectFrm.unid),fetchData2(this.projectFrm.unid)]).then(result => {
const result1 = results[0];
const result2 = results[1];
// 合并两个数组
const mergedUserList = [...result1, ...result2];
// 输出或处理合并后的数组
console.log(mergedUserList);
});
}