彻底搞懂 async await 的return问题
什么是async await?简单的来说 async await就是promise的语法糖,我们可以把它认知为promise的简写,另外你可以将它简单的认为是异步转同步的那么一个解决方案。Async?首先我们来看这一串代码//立即执行函数,不了解的话可以去查一下资料const a = (async () => {return 111})()console.log(a) // Promise
什么是async await?
简单的来说 async await就是promise的语法糖,我们可以把它认知为promise的简写,另外你可以将它简单的认为是异步转同步的那么一个解决方案。
Async?
首先我们来看这一串代码
//立即执行函数,不了解的话可以去查一下资料
const a = (async () => {
return 111
})()
console.log(a) // Promise { 111 }
我们可以看到给函数添加上async之后 返回值即成为了promise对象,正如async译文一样,异步,也就是说我们把这个函数变成了异步promise函数。此时我们再去return 一个值的话,并不会是我们想的那个结果。
当然如果单纯的添加一个async并不是这个函数就成为异步了,不要那么去想,那么去想你就错了
console.log('first') //1
; (async () => {
console.log('tow') //2
})()
console.log('last') //3
如上所示,async函数并没有像异步计时器settimeout一样,挂起,当last执行完成之后再去执行,而是直接输出了,所以我们不要理所当然的去想加上了 async,这个函数就成异步函数了。
当然如果我们不return的话,就是返回一个空的promise对象,其实如果不做啥特殊操作的话,async自己单独使用的话,其实不是特别能显示出它的作用。
Await?
这个时侯我们就应该想到 await了,await是什么?如果promise对象通过then或catch方法又注册了回调函数,async函数执行完以后,注册的回调函数就会放到异步队列中,等待执行。如果只是async, 和promise 差不多,但有了await就不一样了, await 关键字只能放到async 函数里面,await是等待的意思,那么它等待什么呢,它后面跟着什么呢?其实它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果,我们先来尝试这放一个异步fs读取
console.log('first') //
; (async () => {
// 异步读取
const fs111 = await fs.readFile('云开发.txt', function (err, data) {
if (err) {
return console.error(err)
}
return data.toString()
})
console.log(fs111)
})()
console.log('last') //
我们的结果是返回的undefined。那是为什么呢?正如我们上方所说,await等待的是一个promise对象,那么我们的fs是promise对象么,显然并不是,所以await并没有阻塞后方代码执行,因为被挂起了确切地说fs并没有执行完,还没有返回数据data还是空的,所以结果就是空。
解决的办法也很简单,将fs封装成一个promise就可以了,再去执行,console.log()输出就会显示,读取的文件数据。
那么好,简单的介绍完async和await之后,我们其实应该知道最常用的场景是在哪里,其实就是发送ajax请求
这里的请求是 axios 获取数据,然后存入到vue的data中
async leftMenu() {
const { data: res } = await this.$http.get('menus')
this.menuList = res.data
}
因为axios本身返回的就是一个promise对象,await接受的就是成功之后的回调函数数据,在获取到数据之后,我们将其赋值给data中的menuList,这样扎眼一看其实没什么问题,但是我们换种思路 因为本身 async是一个函数那么我们可不可以将获取到的值return出去,然后再从像created中,mounted中直接用this.menuList = leftMenu()呢?
我们可以来模拟尝试一下
const res = async function (a) {
let xiao = await new Promise((resolve, reject) => {
setTimeout(() => {
if (a === 0) {
resolve('你成功获取了数据')
} else {
reject('获取数据失败了')
}
}, 3000)
})
// console.log(xiao)
return xiao
}
const xiaores = res(0)
console.log(xiaores)
结果发现返回的数据是promise,并不是我们想的返回一个你成功获取了数据,这是为什么呢?因为你这个时候要清楚await是promise的语法糖呀!就相当于.then呀,那么then的话,是不是就是异步代码了?这跟settimeout没关系,要知道.then也会被挂起,那么await就不会被挂起了么?我们知道他是一个异步函数之后,执行的是promise,那么他就会去执行,下方的同步代码,这也就导致了,数据其实还没有返还回来,导致无法将异步返回的数据赋值给我们我们想赋予的哪一个值。
解决它也很简单
const res = async function (a) {
let xiao = await new Promise((resolve, reject) => {
// setTimeout(() => {
if (a === 0) {
resolve('你成功获取了数据')
} else {
reject('获取数据失败了')
}
// }, 3000)
})
// console.log(xiao)
return xiao
}
; (async function (a) {
const xiaores = await res(0)
console.log(xiaores)
})()
其实你就可以简单的理解就是调用了他的then方法
const res = async function (a) {
let xiao = await new Promise((resolve, reject) => {
// setTimeout(() => {
if (a === 0) {
resolve('你成功获取了数据')
} else {
reject('获取数据失败了')
}
// }, 3000)
})
// console.log(xiao)
return xiao
}
res(0).then(res => {
const xiaores = res
console.log(xiaores)
})
得到的结果是一样的
总结,其实async await可以return,但是要经历多次嵌套,所以说能别return就别return了。
再给大家放一下今天下午遇到的错误
这其实也是向我们刚才那样,return 一个值,让那后用变量接收,但是返回的值确是空?
因为什么?因为return放在了forEach里,return放在forEach里是没有用的,我们的函数其实并没有返回值,所以结果是空。这个bug,差点整的我怀疑让人生,让我又一次的怀疑,我对async以及await的认知。
所以说写代码还是要认真,加油吧小伙伴么!
提及一下,如果我们想要去遍历中停止请使用 for循环或者 for in for of,甚至 some,every,fliter,map,这些都是可以的,如需了解请关注后续文章
更多推荐
所有评论(0)