1.async关键字的作用
async是异步函数的标识符,说明该函数是个异步函数,返回值是个promise
对象。
function fn1() {
return 1
}
console.log(fn1()) //1
async function fn2() {
return 1
}
console.log(fn2()) // Promise{<fulfilled>:1}
从上面例子可以看到,async
函数的返回值是一个promise
对象,既然是一个promise
对象,那就自然可以使用其原型上的属性,比如then
、catch
等等。
fn2()
.then(r => {
console.log(r) // 1
})
tips:经试验,即使在fn2中return Error('2')也会走到then方法中,是不是说明async函数默认返回的promise状态就是fulfilled?
2.await是什么?
await
是async wait
的缩写,它等待返回的是一个表达式,不管是不是promise
对象都可以,只是说如果返回的是promise
对象执行的状态不一样而已,需要注意的是await
只能在async
函数中使用,看下面例子:
function sync() {
setTimeout(() => {
return 1
}, 1000)
}
async function async1(){
return new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 2000)
})
}
async function test(){
await sync() //undefined
console.log(1)
}
async function test2() {
await async1()
console.log(1)
}
test()
test2()
分别执行test
和test2
函数可发现,在执行test
的时候直接打印了1
,在执行test2的时候是过了2秒才打印出1。
可以看出,如果await
等来的是一个promise
对象,它会"阻塞"后面的代码,直到这个promise
对象有返回结果,不管这个结果是成功还是失败。
如果不是一个promise
对象那么它就是一个同步函数,按照js规则同步执行。
如果不是一个promise
对象,那await
后的表达式就是要等待的东西
之前在这里有个理解错误的地方:我以为如果await
后面如果不是一个promise
对象那么它就是一个同步函数,直接执行后面的代码,其实不是这样,就算不是promise
对象那么await
后面的内容还是相当于在then
执行,跟promise
的区别在于如果等待的是一个promise
对象,那么要等待这个对象解析完成,如果没有resolve
或者reject
那么后面的内容就不会执行,看两个例子:
// eg1
function fn1() {
return new Promise(()=> {
})
}
async function fn2() {
await fn1()
console.log('wait fn1') // 这里的值永远也不会打印,因为函数fn1这个promise对象的状态没有解析
}
fn2()
// eg2
async function fn2() {
await 2
console.log(24) // 先打印
}
fn2()
console.log('this') // 后打印
//等同于
async function fn2() {
Promise.resolve(2)
.then(r => {
console.log(24)
})
}
fn2()
console.log('this')
可以注意到我在test
函数中注释了一个undefined
这是因为await
后的表达式如果是一个函数,它就会立即执行,在sync
函数立即执行后返回的就是undefined
,它不会再等待定时完成后返回的值
- 关于
await
返回值
1.await
后是一个promise
对象,如果是resolve
状态,值就是resolve
参数。如果是reject
状态,会将错误抛出
// resolve
let p = await Promise.resolve(3)
console.log(p) // 3
// reject
let p = await Promise.reject('error')
console.log(p) // 控制台报错
2.await
后不是promise
对象,则返回值就是该值的本身
let p = await 3
console.log(p) // 3
3.错误捕获
Promise
除了resolve
之外还有可能是reject
,那么怎么来处理reject
呢?
- 使用
try catch
捕获
function fn() {
return Promise.reject('error')
}
async function asyncFn() {
try {
await fn()
console.log(1) // 如果上一行出错将直接跳到catch,不会执行到这里
} catch(e) {
console.log(e) // error
}
}
这里可以将可能出现错误的代码放到try
中一旦程序出错,try
后面的代码将不会被执行,直接跳到catch中去
- 使用
promise.catch
捕获
function fn() {
return Promise.reject('error')
}
async function asyncFn() {
await fn().catch(e => console.log(e))
// do something
}
4.使用场景
在业务开发当中,我们可能会遇到比如说,你需要等待A接口请求完成后去执行某个操作,如果不使用await
的话可以直接将操作插入的请求的then
链当中,我们来对比下两种写法。
// 不使用await
function http() {
axios.get('url')
.then(r => {
doIt()
})
.catch(e => {
console.log(e)
})
}
function doIt() {
// do something
}
// 使用await
function http() {
return new Promise((resolve, reject) => {
axios.get('url')
.then(r => {
resolve('success')
})
.catch(e => {
reject('error')
})
})
}
function doIt() {
// do something
}
async function fn() {
let p = await http()
if (p === 'success') {
doIt()
} else {
....
}
}
fn()