当前位置: 首页 > 知识库问答 >
问题:

javascript - await执行时机问题?

艾谦
2024-07-09
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后(下一行)的代码会被放在微任务队列中执行,具体的执行时机是?

共有3个答案

柳墨一
2024-07-09

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 。

漆雕嘉茂
2024-07-09

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

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

胥博文
2024-07-09

回答问题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的回调函数)。

 类似资料:
  • 网址请求顺序是 souhu.com baidu.com tencent.com 这是什么原因呀?

  • 下面这段代码中,为何 ws.send_text("1") 必须等待 load_dataset("beans") 加载完毕才会执行呢? 不应该是先执行 ws.send_text("1") 然后再执行 load_dataset("beans") 吗? load_dataset 是一个 加载模型数据集的函数。

  • 摘要:一个更好的方法,以中止ansible playbook立即,如果任何主机是无法访问。 如果任何一个主机无法访问,是否有方法中止Ansible playbook。我发现,如果它无法到达主机,它仍将继续运行,并执行剧本中的所有播放/任务。 我所有的剧本都指定max_fail_percent为0,但在本例中ansible不会抱怨,因为所有可访问的主机都可以执行所有的剧本。 目前我有一个简单但黑客的

  • 本文向大家介绍探寻Javascript执行效率问题,包括了探寻Javascript执行效率问题的使用技巧和注意事项,需要的朋友参考一下 Javascript是一门非常灵活的语言,我们可以随心所欲的书写各种风格的代码,不同风格的代码也必然也会导致执行效率的差异,开发过程中零零散散地接触到许多提高代码性能的方法,整理一下平时比较常见并且容易规避的问题  Javascript自身执行效率   Javas

  • 最后,/很快将在除IE以外的所有主要浏览器中得到支持。因此,现在我们可以开始使用/编写更易读的代码,但是有一个问题。很多人像这样使用异步等待:

  • 函数recursive 是异步加递归 理想状态是:在函数updateParams调用 await函数recursive执行完后再执行后面代码。 实际:函数recursive还没执行完后面的代码就执行了

  • 请问,在React中, const data = await getData() 这个代码执行的时机是生命周期的哪个点?

  • 我试图在包含GUI系统的JDK 11.0.2上运行我在Intellij中创建的一个可执行jar文件。我已经安装了Java8和java SDK11.0.2。每当我双击jar文件时,我希望主gui登录屏幕出现,但什么也没有发生。我已经尝试了其他选项,例如尝试通过cmd运行它(它给了我一个访问错误),HKEY_CLASSES_ROOT\jarfile已经有命令:“C:\Program Files\jav