async 函数是ES7标准引入的
一、什么是async函数
1、async 让异步代码变得像同步代码一样
- 返回一个promise对象
- promise对象的结果由async函数执行结果的返回值决定
2、Generator 的好基友(语法糖)
虽然说async函数是Generator函数的好基友,但是一点也不省油,首先让我们看一下它们的区别
2.1 好基友的不同点
通过下面两段代码可以发现,async函数就是将Generator函数的星号*替换成async,将yield替换成await
// Generator函数:
function * gen(){
let users = yield getUsers()
let orders = yield getOrders()
let goods = yield getGoods()
}
let iterator = gen()
iterator.next()
Generator函数标志是星号*和yield,通过next()来一步步执行yield操作。
可以说Generator函数是被动型,不喜欢自己动,喜欢被步步紧逼。
但是async函数就是主动型选手了。
const p = new Promise((resolve, reject)=> {
resolve('用户数据')
})
var main = async function () {
try {
let result = await p;
console.log(result) // 用户数据
} catch (error) {
console.log(e)
}
// 通过try...catch捕获reject的返回值
}
main()
async函数自带执行器,一次调用,自动输出,这也是大家更喜欢async函数的原因。
2.2 async函数对好基友Generator进行了改进
- 第一个就是前面说的,async是主动的,自带执行器,而Generator喜欢被动,除非搭配co模块
- async语义更好,async表示有异步操作,await表示屁股后面紧跟的表达式需要结果
- async适用性更广,可谓人见人爱
- async返回值是Promise对象,可用then指定下一步操作,用起来很方便
一句话总结,async函数主动型、人见人爱、好用,接下来就详细说一下async的用法。
二、async函数用法
1、async基本语法
async function fn() {
// 如果函数返回的结果不是promise对象,async返回的结果就是成功的promise对象
// 如果函数返回的结果是一个promise对象,则根据函数内promise的结果判断
// 例如下面的promise函数
return new Promise((resolve, reject)=> {
resolve('成功的数据')
// reject('失败的数据')
})
}
const result = fn()
result.then((value)=> {
console.log(value) // '成功的数据' 如果函数体内的promise返回resolve则走这里
}, (reason)=> {
console.log(reason)// '失败的数据' 如果函数体内的promise返回reject则走这里
})
2、await语法
2.1 await必须写在async函数中
2.2 await右侧的表达式一般为promise对象
2.3 await返回的是promise成功的值
2.4 await的promise失败了,就会抛出异常,需要通过try…catch捕获异常
const p = new Promise((resolve, reject)=> {
resolve('用户数据')
})
async function main() {
try {
let result = await p;
console.log(result) // 用户数据
} catch (error) {
console.log(e)
}
// 通过try...catch捕获reject的返回值
}
2.5 async返回的Promise对象必须等到内部所有await命令后的Promise对象执行完才发生状态改变,即执行then方法指定的回调函数,除非遇到return或抛出错误。
2.6 只要一个await语句后面的promise变成reject,那个整个async函数都会中断执行
async function f() {
await Promise.reject('出错了')
await Promise.resolve('这里不会执行')
}
上面代码中的第二行不会执行,因为第一个await语句状态变成了reject。
有时我们希望前一个promise中断不影响后面的await语句执行,这时需要将await放在try…catch语句中
async function f() {
try {
await Promise.reject('出错了')
} catch (error) {}
await Promise.resolve('这里不会执行')
}
另一种方法是将前面的await语句加上catch方法,处理前面可能出现的错误。
async function f() {
await
Promise.reject('出错了')
.catch(e=> console.log(e))
await Promise.resolve('这里不会执行')
}
3、await实际应用
如果我们有三个登录权限需要去判断,只要命中其中一个就可以退出判断,不再进行其他判断,使用Promise和async实现:
let a = new Promise((resolve, reject)=>{
let status = true
// a权限逻辑判断代码----
if (status) {
resolve(status)
} else {
reject(status)
}
})
let b = new Promise((resolve, reject)=>{
let status = true
// b权限逻辑判断代码----
if (status) {
resolve(status)
} else {
reject(status)
}
})
let c = new Promise((resolve, reject)=>{
let status = true
// c权限逻辑判断代码----
if (status) {
resolve(status)
} else {
reject(status)
}
})
let authList = [a, b, c]
let test = async function(){
for(let auth of authList){
try {
await auth
break
} catch (error) {
console.log(error)
}
}
}
在上面async代码中,如果await操作成功,则会使用break语句退出循环;如果失败,则会被catch语句捕捉,然后进入下一轮循环。