await执行时机问题?

新手上路,请多包涵
console.log('start');

setTimeout(function() {
    console.log('timeout');
}, 0);

Promise.resolve().then(function() {
    console.log('promisel');
}).then(function() {
    console.log('promise2');
}).then(() => console.log(`promise3`))

async function asyncFunc() {
     await asyncSubFunc();
     Promise.resolve().then(x => {
         console.log('async end');
     })
}

async function asyncSubFunc() {
    console.log('async sub');
    return Promise.resolve().then(() => {
        console.log('async sub promise');
    });
}
asyncFunc();

console.log('end');

理想的预期输出:
start
async sub
end
promisel
async sub promise
async end
promise2
promise3
timeout

实际浏览器控制台输出为:
start
async sub
end
promisel
async sub promise
promise2
promise3
async end
timeout

问题1:await后的代码被执行完成后,为什么没有继续往下,而是继续执行微任务队列中的微任务?
问题2:await后(下一行)的代码会被放在微任务队列中执行,具体的执行时机是?

阅读 811
avatarAI BotBETA

回答问题1

在JavaScript中,await会暂停当前async函数的执行,并等待Promise解决(fulfilled)或拒绝(rejected)。但是,一旦await后的Promise解决,async函数并不会立即继续执行后面的代码,而是会先查看微任务队列(microtask queue)中是否有待执行的微任务。如果有,那么这些微任务会在继续执行async函数的后续代码之前先被执行。

在你的例子中,asyncSubFunc返回了一个Promise,当这个Promise解决后(打印出async sub promise),JavaScript引擎会检查微任务队列,并发现由Promise.resolve().then(...)产生的微任务(打印出async end)。因此,这些微任务会先被执行,然后才继续执行asyncFunc后面的代码(如果有的话)。

回答问题2

await后的代码(即await表达式之后的代码)不会被直接放在微任务队列中执行。相反,当await的Promise解决时,JavaScript引擎会查看微任务队列,并执行队列中的所有微任务。一旦微任务队列为空,async函数才会继续执行await之后的代码。

具体的执行时机是:

  1. async函数执行到await表达式时,会暂停执行,等待Promise解决或拒绝。
  2. Promise解决后,JavaScript引擎会检查微任务队列,并执行所有等待的微任务。
  3. 当微任务队列为空时,async函数继续执行await之后的代码。

在你的例子中,由于asyncSubFunc返回的Promise解决后,微任务队列中已经有了由Promise.resolve().then(x => { console.log('async end'); })产生的微任务,所以这些微任务会先被执行,然后才继续执行asyncFunc的后续代码(如果有的话)。但是,由于asyncFunc的后续代码已经是整个代码段的末尾了,所以没有更多代码被执行,而是继续执行了事件循环中的下一个任务(在这个例子中是setTimeout的回调函数)。

2 个回答

你这不存在固定顺序,你多执行几遍,应该会输出结果都不一样。

你这段代码,相当于有3个异步,相当于3个各自执行,谁先谁后不固定。

async function 的返回一定是一个 promise 。这个 promise 会使用函数的返回语句中的值去 resolve。

所以在这里,asyncSubFunc 的 return 后面是一个 promise (记作 promise_return),asyncSubFunc 返回的是另一个 promise (记作 promise_async),这是两个不同的 promise 。并且 promise_return 会用于 resolve promise_async,大致相当于 promise_return 会被添加一个 then 任务,在其中会 resolve promise_async。

await promise_async (promise_async 是 asyncSubFunc 的返回值),大致相当于给 promis_asnyc 增加了一个 then 任务,在其中执行函数剩余部分。

所以从 promise_return resolve 开始(也就打出 "async sub promise" 之后),到 await 语句之后的代码被执行,需要经历两个 then 任务。第一个是 promise_return 的 then 任务,会 resolve promise_async ;第二个是 promise_async 的 then 任务,会执行函数的后续部分。then 任务都是异步的,要等到 promise resolve 之后才会被加入微任务队列,于是,就可以看到其中插入了 promise2 与 promise3 。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏