async/await以及错误处理

1. async

1.1 async可以修饰函数表达式、函数声明、箭头函数和方法

let func = async function(){} //函数表达式
async function foo(){} //函数声明
async () => {} //箭头函数
class Person{
	async methodA(){} //方法
}

1.2 async里面的代码还是同步执行的

async function foo(){
    console.log(2)
    return 3
}
foo().then((val) => {
    console.log(val)
})
console.log(1)
/** 
* 输出:
*  2
*  1
*  3
**/

1.3 async修饰的函数返回值不同场景

async修饰的函数返回值期望是实现thenable的接口的对象,但是常规值也可以,如果返回的是实现了thenable接口的对象,那么这个对象可以通过then进行解包输出;如果是常规值,那么会返回一个解决的期约

①没有返回值,会返回一个Promise.resolve(undefined)的期约

async function foo(){
    console.log(2) 
}
console.log(foo()) //Promise { undefined }

②如果有返回值a,会返回一个Promise.resolve(a)的期约

async function foo(){
    console.log(2)
    return 3
}
console.log(foo())//Promise { 3 }

③抛出异常:throw ‘err’,会返回一个Promise.reject(‘err’)的期约

async function foo(){
    throw 'err'
}
console.log(foo())//Promise { <rejected> 'err' }

④函数内部执行Promise.reject(‘test’),但是这个拒绝期约不返回,那么返回的仍然是Promise.resolve(undefined)的期约(很容易理解,不返回值默认就是返回不包装任何值的期约),并且异步函数里面的拒绝期约无法捕获

async function foo(){
   Promise.reject('a')
}
console.log(foo())//Promise { undefined }
foo().catch(console.log)//无法捕获,异常照样抛出

⑤异步函数返回一个拒绝期约,那理所当然会接收到一个拒绝期约,可以用catch捕获

async function foo(){
   return Promise.reject('a')  
}
let p = foo()
setTimeout(() => {
 console.log(p)   //Promise { <rejected> 'a' }
});
foo().catch(console.log)//解包输出:1

⑥异步函数返回resolve的期约,自然也是接收一个resolve的期约:

async function foo(){
    return Promise.resolve('a')
 }
 let p = foo()
setTimeout(() => {
    console.log(p)   //Promise { 'a' }
});
foo().then(console.log)//解包输出:a

⑦返回一个实现thenable接口的对象

async function foo(){
    const thenable = {then(callback){
        callback('baz')
    }}
    return thenable
}
let p = foo()
setTimeout(() => {
 console.log(p) //Promise { 'baz' }  
});
foo().then(console.log)//解包输出:baz

2. await

2.1 await只能在async函数中使用,它会暂停async函数中后面代码的执行,等待await后面的代码执行完

async function foo(){
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('xixi')
            resolve(3)
        }, 1000);
    })
    console.log(await p)
    console.log('haha')
}
foo()
//输出:
xixi
3
haha

上面的例子,如果不使用await,p会输出一个pending的期约,然后会先执行setTimeout后面的代码:'haha’的输出,最后再输出xixi , 执行结果是:
Promise { }
haha
xixi

2.2 await后面期望是一个实现thenable接口的对象,也可以是常规的值

await后面期望是一个实现thenable接口的对象,也可以是常规的值,如果是常规值,那么这个值会被当成一个已经解决的期约。如果实现了thenable接口,await会对对象进行“解包”,“解包”可以理解为解开需要then()执行才能拿到值的包装,如果是Promise.resolve(xxx),解包操作就是直接获取到xxx,如果Promise.reject(3),解包操作就是直接把reject的异常同步抛出(可以try catch获取,如果没有await,reject的期约是无法try…catch捕获的,只能通过then()解包)
① await 一个promise

//1、resolve的promise
async function foo(){
    let p = Promise.resolve(3)
    console.log(await p)//3
}
foo()
//2、reject的promise
async function foo(){
    let p = Promise.reject(3)
    try{
        await p
    }catch(e){
       console.log(e) //3
    }
}
foo()

② await一个普通的实现了thenable接口的对象

async function baz(){
    const thenable = {then(callback){
        callback('haha')
    }}
    console.log(await thenable)
}
baz()//输出:haha

③await一个常规值

async function foo(){
    console.log(await 3)
}
foo() // 输出:3

④await 一个throw error,因为throw error在async中实际上是返回一个reject的期约的,所以等价于await一个拒绝的期约

async function foo(){
   try{
    await(() => {throw 3})()
   }catch(e){
    console.log(e)//输出:3
   }  
}
foo()

2.3 await对代码执行顺序的影响

异步函数中遇到await,会做一个标记,暂停异步函数的执行,等待await后面的值执行,在等待的过程中,如果有同步代码没有执行完,会先执行完同步代码,另一边,await后面的值如果可用了,js程序会把await后面的值放到消息队列,等同步代码执行完后,js程序从消息队列中拿await后面的值,然后继续执行异步函数后面的代码,举例:

async function bar(){
    console.log(4)
    console.log(await 6)
    console.log(7)
}
console.log(1)
bar()
console.log(3)

输出:
1
4
3
6
7

3、错误处理

参考:https://cloud.tencent.com/developer/article/1470715
因为await返回的是一个promise,所以每一步await都有可能出错(返回reject的promise),为了捕获这些错误,我们使用try。。。catch。。

async function getUserInfo (cb) {
  try {
     const id = await request.getCurrentId()
  } catch(e) {
     return cb('an error in getCurrentId')
  }
  
  try {
    const info = await request.getUserInfo(id)
  } catch(e) {
    return cb('an error in getUserInfo')
  }

  return cb(null, info)
}

这样如果一个异步函数中有很多await,我们每一个都try…catch…,代码看起来很不整洁,也很难维护,基于这个可以用这种方式处理:

async function getUserInfo() {
  try {
    const id = await request.getCurrentId().catch(err => Promise.reject('an error in getCurrentId'))//这里如果有异常,在catch里面做个基本处理,继续抛出
    const info = await request.getUserInfo(id).catch(err => Promise.reject(() => {
    doSomething()
    anotherErrorHandler()
})//在catch里面做个基本处理,继续抛出
  } catch(err) {
  //统一处理异常
    if (typeof err === 'function') err()
    else errorHandle(err)
  }
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值