JS之异步请求async/await(下)

735 阅读2分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

async/await

根据MDN的定义,async是一个通过异步执行并隐式返回Promise作为结果的函数。异步执行和隐式返回Promise怎么理解。

隐式返回:可以看到async标记的函数执行后最终返回的是一个Promise对象。

async function foo(){
  return 2 
}
console.log(foo()) //Promise {<fulfilled>: 2}
foo().then((val)=>{console.log(val))} //2

对应Promise的写法

function foo(){
  return new Promise((resolve)=>{
    resolve(1)
  })
}
console.log(foo()) //Promise {<fulfilled>: 1}
foo().then((val)=>{console.log(val)}) //1

await,async函数返回的是一个Promise对象,结合下面代码体会一下await是什么

async function foo() {
    console.log(1)
    let a = await 100
    console.log(a)
    console.log(2)
}
console.log(0)
foo()
console.log(3)

结果是: 0 - 1 - 3 - 100 - 2

结合一下之前说的协程的概念, 此时外部环境就是父协程, 而foo就是子协程

  1. 首先执行了console.log(0)

  2. 然后父协程将线程执行权交给了foo协程, 由于foo 函数被async标记过, JavaScript 引擎会保存当前的调用栈等(相当于有个独立的调用栈)信息, foo协程执行了console.log(1), 此时遇到了await 100, 此时foo协程创建了一个promise

    let promise_ = new Promise((resolve,reject)=>{
      resolve(100)
    })
    

    可以看到在 executor 函数中调用了 resolve 函数,JavaScript 引擎会将该任务提交给微任务队列.

    然后JS引擎会暂停当前foo协程的执行, 将主线程的控制权交给父协程执行, 同时将这个新建的promise_对象返回给父协程 , 此时父协程还有一件事, 就是用promise_.then中的回调函数来监控promise_状态的改变

  3. 此时父协程就接着执行console.log(3), 并且打印出来3 , 随后父协程即将执行结束, 在结束前, 就会检查是否有微任务, 开始执行微任务队列, 微任务队列中有一个resolve(100)的任务等待执行, Promise_执行之后的触发promise_.then 中的回调函数

    promise_.then((value)=>{
       //回调函数被激活后将主线程控制权交给foo协程,并将vaule值传给协程
    })
    

    该回调函数被激活以后,会将主线程的控制权交给 foo 函数的协程,并同时将 value 值传给该协程。foo 协程拿到主线程执行权后,会把得到的 value 值赋给了变量 a,然后 foo 协程继续执行后续语句console.log(2),执行完成之后,将控制权归还给父协程。

    这么看来await就是promise.then

总结一下: await之后的行为实际上就是让子协程创建了一个promise.resolve(), 然后返回给了父协程微任务队列, 当父协程要执行微任务队列的时候, 触发promise_.then的回调函数, 然后在回调函数中将执行权和返回值都交给子协程 .