背景
vue2,异步操作并行运行
需求
某个页面现时需要一些接口请求回来的枚举值作为查询条件可供选择,然后将这些查询条件作为入参,请求列表数据。这就造成了我需要先调用枚举值接口,等枚举值接口调用完了,再调查询接口。
错误示例1
如下代码,我希望等this.getMapList()里面的接口全部调用完成后,再执行 this.handleMapData()和 thi.getList()。
async mounted() {await this.getMapList()this.handleMapData()this.getList()
},
methods() {// 这两是枚举值接口getIndustryList() {service.queryIndustryStyleList().then(res => {this.industryStyleList = res.resultconsole.log(this.industryStyleList, 'industryStyleList')resolve()}).catch(err => {console.log('111', err)this.industryStyleList = []EMessage(err.error_info, 'error')})},getInvestList() {service.queryInvestStyleList().then(res => {this.investStyleList = res.result }).catch(err => {console.log('222', err)this.investStyleList = []EMessage(err.error_info, 'error')})},getMapList() {this.getIndustryList()this.getInvestList()},// 这是列表接口getList() {service.queryTableList({...this.form,}).then(res => {this.tableData = res.result}).catch(() => {this.tableData = []}) },// 这是处理枚举值数据的方法handleMapData() {this.industryStyleList = ...this.investStyleList = ...}
},
我通常会像上面那样写,一直以来都没有什么问题,getList接口都是在两个枚举值接口之后调用的。但这次枚举值接口没通的情况下,我发现在对枚举值数据做处理的this.handleMapData()会先于this.getMapList()执行,这可能会出现不能及时更新枚举值数据。
错误示例2
我尝试把this.getMapList()放在created里面,期待created比mounted先调用,这样就可以保证 this.handleMapData()和 this.getList()一定是在后执行的了
async created() {await this.getMapList()},
async mounted() {this.handleMapData()this.getList()
},
但是!!!在vue的生命周期钩子中,created 和 mounted 是两个不同阶段的钩子,created 先于 mounted,且它们是异步执行的。尽管created的await会暂停created内部代码的执行知道getMapList解决,但这并不影响mounted的执行时机。created钩子中的await只会影响created钩子内的代码执行顺序,mounted钩子会按预期在created后执行,而不会等待created钩子中的异步操作完成。
正确写法
1、首先要确保this.getMapList()里面的两个接口是异步执行的,因为他两谁快谁谁慢都无所谓,只要在this.handleMapData()执行前拿到数据就行。所以getInvestList和getIndustryList的接口调用绝对不能使用try catch,因为那样会造成必须等getIndustryList执行完才能执行getInvestList
2、我期望并行的运行getInvestList和getIndustryList,并等待他们全部全部完成。这就可以用Promise.all()
3、Promise.all()接受一个promise数组作为输入,并会返回一个新的promise,这个新的promise会在所有输入的promise都成功解决后解决,其解决值是一个数组,包含了所有输入promise的解决值(按相同的顺序),如果输入的任何一个promise被拒绝,则返回的promise会立即被拒绝,并带有第一个被拒绝的理由。
4、由于Promise.all()输入的一个promise被拒绝,但其他promise可能成功,所以我选择把在每个请求的.catch中做错误处理,这样无论Promise.all()里的请求是否成功,都会在全部完成后执行this,handleMapData()和this.getList()
async mounted() {try {const promises = [ // 必须在这.catch,这样才能无论成功与否都执行handleMapData和getListthis.getIndustryList().catch(() => {}), this.getInvestList().catch(() => {}), ]await Promise.all(promises)this.handleMapData()this.getList()}catch(err) {}
},
methods: {getIndustryList() {return service.queryIndustryStyleList().then(res => {this.industryStyleList = res.result}).catch(err => {console.log('111', err)this.industryStyleList = []EMessage(err.error_info, 'error')})},getInvestList() {return service.queryInvestStyleList().then(res => {this.investStyleList = res.result }).catch(err => {console.log('222', err)this.investStyleList = []EMessage(err.error_info, 'error')})},// 这是列表接口getList() {service.queryTableList({...this.form,}).then(res => {this.tableData = res.result}).catch(() => {this.tableData = []}) },// 这是处理枚举值数据的方法handleMapData() {this.industryStyleList = ...this.investStyleList = ...}
}