async/await 执行顺序问题

新手上路,请多包涵

题目描述

async function foo() {
    return Promise.resolve(300)
    // return 300 // ❓问题:上下两种写法执行结果不一致的原因是什么呢?return 300 不等价于 return Promise.resolve(300) 吗
}
// debugger
;(async function () {
    console.log("start") // 1. 立即执行函数 会先执行这一步
    const p1 = Promise.resolve(100)
    const data1 = await p1 // 2. 遇到 await 后面代码放入微任务队列 第一位
    console.log("data1", data1) // 5. 同步代码执行完成 进入微任务队列 打印 data1 100
    const data2 = await 200 // 5. 执行 Promise.resolve(200) 之后代码放入微任务队列 第三位
    console.log("data2", data2) // 7. 进入微任务队列 打印 data2 200 
    const data3 = await foo() // 8. 执行foo() 之后代码放入微任务队列第四位
    console.log("data3", data3) // 9. 打印
})()
const res = foo()
console.log(res) // 3. 继续执行同步代码 执行此句 打印一个 promise
res.then((data) => { // 4. 我认为这是promise的状态已经是resolve,所以应该放入微任务队列的第二个位置 ❓问题:但实际上并不是这样,为什么?
    // ⚠️ 这个要等res 完全resolved之后才会执行 ❓问题:到底什么时候会被resolved 呢?
    console.log("data", data) // 6.执行微任务队列第二位 打印 ❓问题:为什么 data 200 在data1 data2 之后打印, 在data3 之前打印呢?
})

当foo()内返回return Promise.resolve(300)时如下图

image.png

当foo()内返回return 300时如下图,这个图与我理想的执行结果一致

image.png

自己的思路

我的思路、执行顺序都在代码注释里

你期待的结果是什么?实际看到的错误信息又是什么?

我期待的结果是:foo()方法中代码为 return Promise.resolve(300) 的时候返回值如下

start
Promise {<fulfilled>: 300}
data1 100
data 300 // 这个应该 优先
data2 200 // 这个应该 落后 实际不对
data3 300

实际错误信息如上面的图一

阅读 2.6k
2 个回答

不好意思,来晚了。

问题的关键点是 async 的实现和 await 的实现不同,也可以说是语义不同,前者采用的 RESOLVE 语义,后者采用的是 Promise.resolve 语义,RESOLVE 语义比 Promise.resolve 语义,在处理 promise 要慢一拍。

我之前在博客里有提到类似的例子

const p1 = Promise.resolve(1)
const async1 = async () => {
  return p1
}
async1().then(res => {
  console.log(res)
})
p1.then(res => {
  console.log(2)
}).then(res => {
  console.log(3)
})

最终等价于

const p1 = Promise.resolve(1)
const async1 = () => {
  return new Promise(resolve => {
    return Promise.resolve().then(() => {
      p1.then(resolve)
    })
  })
}
async1().then(res => {
  console.log(res)
})
p1.then(res => {
  console.log(2)
}).then(res => {
  console.log(3)
})

就是解释的 async 的语义和实现问题,题主可以去翻一下就能明白了。

Promise.resolveasync 函数都可以看成是语法糖
你要的等价关系其实是这样:

Prmise.resolve(300)
//等价于
(function(x){
  return new Promise(function(ok){
    return ok(x)
  })
})(300)

async foo(){return 300}
//等价于
function(){
  function foo(){return 300}
  return new Promise(function(ok){
    return ok(foo())
  })
}

我相信这可以回答你 return 300return Promise.resolve(300)的区别;
虽然你可以一眼看出来, 但编译器是要按套路走的.
同样的 await 关键字后面不管跟什么, 都是要多套一层的.
至于后面问题,都和这些有关;

为什么编译器那么傻,不智能一点?
为了所有Promise实现能互通, ES6 的Promise 也遵从Promise/A+规则;
你可以脑补一下这段代码的结果;

var p1 = Promise.resolve(1)
p1.then = (ok)=>ok(2);
console.log(p1);
Promise.resolve(p1).then(console.log)
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题