使用场景:A函数向后台请求得到数据dataA,B函数需要利用到数据dataA立即进行一些计算或者向后台请求别的数据,这时候写
this.A();
this.B();
会报错,因为异步的原因,执行B的时候A的数据还没返回。
方法1
首先执行的函数A:
A() {
const params = {
projectName: this.listSearchKey
};
// 利用promise
return new Promise((resolve, reject) => {
// 异步请求
projectList(params)
.then(res => {
if (res.code === '0') {
this.dataA = res.data;
// 返回想要的数据
resolve(this.dataA);
}
})
.catch(err => {
console.error(err);
});
});
}
接着执行的函数B
B(id) {
//用到了函数A的返回数据dataA,并且希望拿到返回数据之后立即执行
const params = {
projectId: id || this.dataA[0].projectId
};
taskList(params)
.then(res => {
if (res.code === '0') {
this.tableData = res.data.list;
this.total = res.data.total;
}
})
.catch(err => {
console.error(err);
});
},
在执行时这样写
A().then(val => {
B();
});
方法2
async function asyncMain(){
try{
let result =await A();
result = await B();
}catch(err){
console.error(err);
}
}
asyncMain()
完整的异步转同步实现
想要实现真正的异步转同步实现,可以选择使用promise或者其 all/race、async/await。如果单纯的相互依赖的接口只有两个接口,那么只需要按照上述操作即可。
但是如果存在多个相互依赖的接口,那么可能需要使用
promise.all/race或者async/await。
需要注意的是,如果使用上述方法,那我们就必须让每一个接口函数返回的是 promise 对象,返回promise.resolve 对象便于让程序继续执行,promise.reject可以让 promise.all/race 或者 async/await 更好的捕捉错误。
那么,完成这样的工作需要以下几步:
第一步:让每一个异步函数返回 promise 对象,并且有条件的返回 resolve 或者 reject;
// 接口1
handleData() {
return new Promise((resolve, reject) => {
taskDetail()
.then(res => {
// code非0的时候,表明接口报错,需要reject
if (res.code !== '0') {
reject(res.msg);
return;
}
// 当前为正常状态,resolve即可
this.ftpInfoOptions = res.data;
resolve();
})
.catch(err => {
// catch 时也需要reject
return reject(err);
});
});
},
// 接口2
getSystemOptions() {
const params = {
apsRole: 0,
taskType: this.taskType
};
return new Promise((resolve, reject) => {
getApSystemByApsRoleAndTaskType(params)
.then(res => {
if (res.code !== '0') {
reject(res.msg);
return;
}
this.systemOptions = res.data;
resolve(res.data);
})
.catch(err => {
return reject(err);
});
});
},
第二步,确认多个异步函数之间的依赖关系,选择方法。
上述两个接口是,详情接口以及获取接收方接口,当然详情接口依赖于多个接口,在此只举例一个接口;
公司的业务流程时,编辑某条消息时必须在详情 之前获取很多接口,以便于让数据回显,我们选择了使用async/await,除了彼此依赖的关系以及有先后顺序,还会考虑到如果前置接口异常,剩下的接口就没有必要调用了。
新建某条消息又会考虑到,某一个接口不应该堵塞掉后面的接口,所以选择了promise.all。
// 写在created里面
async created() {
// 判断是否为编辑态
const isEdit = this.taskId !== `null`;
try {
// 这两个接口无论编辑新建,都是前置条件,必须在最前面调用,有先后顺序
await this.getSystemOptions();
await this.getReceiverOptions();
// 详情接口,编辑才调用
isEdit && (await this.handleData());
} catch (error) {
// 承接接口的 reject
console.error(error);
}
// 如果有异步操作在进行之前,必须拿到其他多个异步接口的数据且不分先后,则选择all的方法
Promise.all([
!isEdit ? this.getFtpInfo('add') : '',
!isEdit ? this.getCstoreInfo({}) : '',
])
.then(() => {
// 拿到之后的操作
})
.catch(error => {
// 如果两个接口报错,只能catch到一次
console.error(error);
});
},