问题场景
vue中,我们像后台请求数据时,使用的是axios
,由于请求是需要花费时间的的,而且这个时间还不少(http请求消耗的时间比较长),所以axios发起请求后会立马返回一个Promise对象,然后往下执行js语句。
在Promise对象中进行http请求,请求成功后在.then(callback)
中能够拿到请求结果。
let user
console.log('请求前的代码')
this.$http.post('/api/user/get', {Id: '00001'}).then((res) => {
user = res
console.log('请求结果:' + res)
})
console.log('请求后的代码,请求结果:' + user)
以上代码,假设获取用户信息需要1s,远大于其他js代码的执行时间,那么最终输出顺序是什么?
请求前的代码
请求后的代码,请求结果:undefined
请求结果:{"Id": "00001", .... }
没错,程序会先执行js代码,而变量赋值在请求成功后,所以我们无法保证在请求外能够拿到请求结果。这是异步非常容易产生的问题。
如果我们的业务逻辑需要请求多个数据,并且后一个请求依赖于前一个请求的结果,这时候我们更不能保证数据获取顺序,因此我们需要将异步请求改成同步,以保证业务逻辑的正确性。
async 与 await
async 意为:异步的,其放在我们所定义的function
名前,如:
async getUser() {}
其声明这个函数为一个异步执行的,也就是说 我们调用这个方法时,其返回就是一个Promise对象,显然axios的请求方法,就是通过这个关键字来实现异步的。他的好处就是让程序快速执行,避免用户等待页面加载的时间过长,当然现在我们不想讨论他的优点,他的缺点就是我们现在遇到的问题,我们想要拿到数据再执行下一行代码。
await 意为等待,显然 异步执行的方法,能够通过这个关键字,等待请求结果,实现将异步执行的方法变成同步的。
好了,问题解决,只要在请求时加上await
就可以了!
console.log('请求前的代码')
let user = await this.$http.post('/api/user/get', {Id: '00001'})
console.log('请求后的代码,请求结果:' + user)
结果输出:
请求前的代码
请求后的代码,请求结果:{"Id": "00001", .... }
是的,结果确实是正确的,但还有一个规则还没有讲,那就是 async 与 await 必须同时出现 所以我们的代码实际是这样:
asycn getUser() {
// ... 其他代码
console.log('请求前的代码')
let user = await this.$http.post('/api/user/get', {Id: '00001'})
console.log('请求后的代码,请求结果:' + user)
// ... 其他代码
}
如果有多个请求需要同步:
asycn getUser() {
// ... 其他代码
console.log('请求前的代码')
let user1 = await this.$http.post('/api/user/get', {Id: '00001'})
console.log('请求后的代码,请求结果:' + user1)
let user2 = await this.$http.post('/api/user/get', {Id: '00002'})
console.log('请求后的代码,请求结果:' + user2)
let user3 = await this.$http.post('/api/user/get', {Id: '00003'})
console.log('请求后的代码,请求结果:' + user3)
// ... 其他代码
return [user1, user2, user3] // 假设返回一个数组
}
如果还要嵌套一层
asycn getUser(){
...
},
async getDep(users) {
let dep1 = await this.$http.post('/api/dep/get', {Id: users[0].DepId})
let dep2 = await this.$http.post('/api/dep/get', {Id: users[1].DepId})
let dep3 = await this.$http.post('/api/dep/get', {Id: users[2].DepId})
return [dep1, dep2, dep3]
},
async getData() {
let users = await getUser()
let deps = await getDep(users)
// ... 其他代码
}
Vue中使用
vue项目中,需要使用到同步的,通常也只有页面渲染时的数据初始化。
我们可以定义一个异步方法,将需要同步的请求都放到其中执行
export default {
mouted () {
this.initData()
},
methods: {
async initData() {
let users = await getUsers()
await getDeps(users)
},
async getUsers() {
...
},
async getDeps(user) {
...
},
// ...
}
}
钩子mouted
由于不能使用await
,所以需要定义一个异步的initData()
方法进行数据的初始化。
我可能啥都不会,希望朋友点评......