JS核心-异步编程中的async/await

目录

背景

Await/async与Promise比较

Await/async搭配Promise.all()使用

注意事项

代码执行顺序

缺陷


背景

上文提到的Promise用来处理异步操作结果,配合then注册回调函数, 形成链式调用,让代码易读。除此之外, JS还提供了一个语法糖async/await对Promise使用进行封装,可使异步代码看起来像同步代码的样式,使得代码容易阅读和维护。本文介绍Async/await的使用和注意事项。

Await/async与Promise比较

   /**
     * 加载活动列表(其中先加载群组以得到活动的头像)
     */
    fetchGroupAndActivities: function(){
      if(this.data.isLogin) {
        var that = this
        getGroups() //先加载群组列表的头像。
        .then((res)=>{
          if(res.data.code == "10000") { 
            ...
            return getActivities()  //其次,加载活动列表
          }
        })
        .then((res)=>{ //链式调用,处理活动列表数据。
          if (res.data.code == "10000") {
          ...
          }
        })
        .catch((err) => { //统一捕获异常。 上面then中的任意回调发送异常,会直接中断调用链,在这里处理。
          console.log("get act and group failed...")
        })

使用Await/async重构后的代码形式

 /**
     * 加载活动列表(其中先加载群组以得到活动的头像)
     */
    fetchGroupAndActivities: async function(){
      if(this.data.isLogin) {
        try {
         var res = await getGroups() //1. 异步加载群组列表。
         if(res.data.code == "10000") { 
            ...
           var activitiesRes= await getActivities()  //2.异步加载活动列表
           if (activitiesRes.data.code == "10000") {
           ...//处理活动列表数据
           }
         }
        
        } catch(e) {  
           console.log("get act and group failed...e = " + e) //统一处理异常 
      }
    }
       
    
  1. 如果略过async和await,上面的代码风格看起来和同步代码一样。
  2. async声明的函数,一定会返回一个promise,也就是说这个函数返回后,可以调用.then进行链式调用,如下代码代码所示:
    fetchGroupAndActivities()
     .then(() => { console.log("address groups and activities.") })
  3. await关键字用来声明一个返回promise的异步操作。它可以挂起函数,允许其他函数代码得到执行,直到异步操作返回结果(promise为fulfiled状态)。async函数继续从await语句下一行开始执行。

Await/async搭配Promise.all()使用

需求:获取群组列表和活动列表

分析:两组数据源,全部的结果返回后,再依次消费这些结果。

代码:

async function fetchIndexList() {
    var results = await Promise.all([getGroups, getActivities])
    return results //这里被js自动封装成Promise
}

可以看到如果用Promise.all()API,代码行数少。如果不用Promise,改怎么写?

async function fetchIndexList() {
    var groups = getGroups();
    var activities = getActivities();
    var result1 = await groups
    var result2 = await activities
    return [result1, result2]//这里被js自动封装成Promise
}

注意事项

  1. 关键字await必须在async异步函数内使用。 
  2. async函数的返回值,是一个promise对象。如果用户没有返回或者返回普通对象,js环境打包时会自动为你包装一个promise的对象。

代码执行顺序

  • async函数执行时,在遇到await关键字之前,它与调用它的函数,都是同步运行的。
  • 当遇到await关键字,async函数将被挂起,且释放cpu控制权,允许其他函数继续执行, 直到await声明的异步函数返回结果。一旦完成,程序将从await语句下一行代码开始执行。

缺陷

  1. await不正确使用带来的阻塞问题

通过一个计时器代码来测量await可能带来的速度问题。

1. 定义计时器A

function A(){
   return new Promise((resovle, reject) => {
        setTimeout({
            resolve()
        }, 3000)
    })
}

2. 定义计时器B

function B(){
   return new Promise((resovle, reject) => {
        setTimeout({
            resolve()
        }, 3000)
    })
}

3. 启动两个计数器,统计总共消耗多少时间

async function startTimer(){
      var startTime = new Date()
      var resultA = await A()
      var resultB = await B()
      setTimeout({
        var finishTime = new Date()
        var totalTime = finishTime - startTime
        console.log("totalTime = " + totalTime)
      },3000)
}

startTimer()

   上述代码执行后,计时器总共耗时大于9s。 await标记的异步任务会一个等待前一个await标记的任务执行完毕,如果await依赖过多,产生的执行时间可能更长。有时候你只是想让promise同时执行,有没有一种办法减少时间消耗?解决办法:

async function startTimer(){
      var startTime = new Date()
      var resultA = A()
      var resultB = B()
      await resultA
      await resultB
      setTimeout({
        var finishTime = new Date()
        var totalTime = finishTime - startTime
        console.log("totalTime = " + totalTime)
      },3000)
}

startTimer()

把代表计时器的Promise保存在变量里面,然后再去等待他们的结果。

这样看起来三个计时器Promise是同时启动,它们也将同时完成。最终输出的totalTime大约只有3s。

2. await必须和async搭配使用,违背的代码设计原则, async和await耦合起来了,开发者容易忘记声明async,造成错误。

 总结

本文介绍了JS异步编程中的语法糖await/async来包装Promise,使得异步代码看起来像同步代码的风格,让代码变得简洁。同时介绍了async函数执行的流程,以及使用await可能带来的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值