async function_Async、Await 从源码层面解析其工作原理

be7db482b25f0e14229ece64d3a900d2.png
温故而知新,当我再次遇到 Async、Await 时对其中的细节有些许遗忘。所以写下这篇之前就该写下的文章。

利用 Babel,将 Async、Await 进行转换,可以发现 Async、Await 利用了 switchcase、promise 来达到流程控制。如下是一段使用了 Async、Await 的函数:

async 

为了方便理解,下面只给出核心部分代码。

前面的 name 函数经过 Babel 转换后(后面不说明,name 函数均指被 babel 转换后的 name 函数),得到如下的代码:

...

函数体分段

可以看到经过转换后的函数将 async 函数体内部分成了几个部分,分别为 await 部分、return 部分、async 流程控制结束部分(即 case "end")。如下图所示:

af98a54501f56db5938034b0154b1e0e.png

Async 函数就是将函数体内部进行拆分,这样就可以进行流程控制,例如 case 0 执行后,可以等到合适的时机去执行 case 1。

那么这个合适的时机是什么呢?其实这个时机并不是 async 内部决定的,而是由执行的内容决定,例如发一个异步请求,需要等到请求返回之后才会进到下一个 case。

下面介绍 Async 如何利用 promise 来实现等待,并且等待完成后如何进到一下个 case。

流程控制

要实现流程控制还需要 regenerator-runtime 这个 generator、Async 函数的运行时,它负责将 name 函数进行包装,并添加一些流程控制所需的必要信息。例如 _context:

{
  

另外还需要 _asyncToGenerator、asyncGeneratorStep 这两个 Babel 的 helper,在流程控制中也起到了关键的作用。

用它们在 regenerator-runtime 的基础之上,再包装一层得到一个最终包装好的函数,所以 name 函数实际执行时,调用的最终是这个函数。它的大致内容如下:

...

这里的第三步是 Async 函数的精华,Promise.resolve(value).then(_next) 中的 value 是每个分段最后的 case 所返回的值,如果是一个 Promise 则等到它 resolved 后将 .then 添加到微任务队列,否则直接添加,因为 .then 是一个微任务,当执行到它时会执行 _next ,便开始执行下一个 case。

async 

上面的代码经过转换后如下

function 

别忘了前面说过的最终被包装后的函数,实际执行的是被包装过的函数,所以我在这里说的 async1、async2 执行实际上是执行最终的被包装过的函数,被包装后的函数会在内部调用 async1、async2。

  1. 第一步调用 async1(),执行_next 函数,进入 async1 的 case 0 并打印 'async1 start',设置 _context.next 为 3,即下一步要走的 case 为 3
  2. 执行 return async2(),执行_next 函数,进入 async2 的 case 0 并打印 'async2',由于没有 return,直接进到 case "end"。这个时候会把 done 设置为 true,接下再次进入到 _next,根据 done 的值可以得到能直接结束整个流程,于是执行 resolve(value),async2 函数执行完毕。接下来回到 async1 中的 return async2(),async2 返回的是一个 Promise,所以这里 return 了一个已经 resolved 的 Promise。
  3. 此时 async1 的 case 0 执行结束,return 的 value 是一个 Promise,接下来再次进入 _next,由于还未走到 case "end",所以 done 为 false,所以执行 Promise.resolve(value).then(_next),由于 value 是已经 resolved 的 Promise,所以直接将 .then 添加到微任务队列中。由于还有同步任务未执行完,所以微任务队列还不会被执行,所以此时将权限交给 async1 函数的外部去执行。
  4. 执行 new Promise 并打印 'promise1' ,并将 .then 添加到微任务队列中去
  5. 同步代码执行完毕,开始执行微任务,首先执行之前 async1 添加进去的 _next,此时走到 async1 的 case 3 并打印 'async1 end',然后紧接着到 case 'end',最后当再次走到 _next 的时候发现 async1 可以结束,于是直接 resolve 结束执行
  6. 执行第二个微任务,打印 'promise'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值