代码片段如下所示:

console.log('test')

async function async1() {
    console.log('before wait');
    await wait();
    console.log('after wait');
}

async function wait() {
    try {
        return await new Promise((res, rej) => {
            console.log('wait');
            rej('reject');
        });
    } catch (reason) {
        console.log(reason);
    }
}

async function test() {
    async1();
    console.log('before resolve');
    await Promise.resolve();
    console.log('after resolve');
}

test();

console.log('test end');

您还可以在playground中运行代码

实际结果:

[LOG]: "test" 
[LOG]: "before wait" 
[LOG]: "wait" 
[LOG]: "before resolve" 
[LOG]: "test end" 
[LOG]: "reject" 
[LOG]: "after resolve" 
[LOG]: "after wait" 

我以为after wait会先打印,因为它很早就被推入微任务队列中了?

我哪里错了?


我听取了@Seblor的建议

如果您用THEN函数替换异步/等待,情况可能会变得更清楚.

然后,我删除了所有的异步/等待

console.log('test')

function async1() {
    console.log('before wait');
    return wait().then(() => {
        console.log('after wait');
    })
}

function wait() {
    return new Promise((res, rej) => {
        console.log('wait');
        rej('reject');
    }).catch((reason) => {
        console.log(reason);
    })
}

function test() {
    async1();
    console.log('before resolve');
    Promise.resolve().then(() => {
        console.log('after resolve');
    })
}

test();

console.log('test end');

然后我意识到推送到微任务队列中的第一个代码是catch中的代码,然后是console.log('after resolve'),最后是console.log('after wait')

推荐答案

好的,我好不容易才发现,但我想我明白了.

所以我们都同意问题所在,你看到的问题是,拒绝promise 是在promise 解决之前执行的,但是‘解决后’在‘等待之后’之前打印.

问题是,即使有2个promise ,这里也有3 micro tasks个promise .第一个是return await new Promise(,第二个是await Promise.resolve(),第三个是函数调用的等待:await wait().

wait()的调用返回一个Promise,您将对其进行await,从而创建一个在await Promise.resolve()之后排队的新微任务.

因此,拒绝promise 完成,打印‘拒绝’,然后解决promise 完成,打印‘解决’,最后等待从wait()返回的promise ,打印‘后等待’.

如果您将Async/AWait替换为then函数,可能会变得更清楚.所以这就是:

async function async1() {
    console.log('before wait');
    await wait();
    console.log('after wait');
}

会写成这样:

function async1() {
    console.log('before wait');
    return wait().then(() => {
        console.log('after wait');
    });
}

因此,按照执行顺序(仅限微任务):

  1. await new Promise((res, rej) => {登记第一个promise
  2. await Promise.resolve()登记第二个promise
  3. 第一个promise 被拒绝,打印‘拒绝’
  4. 由于第一个promise 返回,我们最终可以registerthen回调,创建第三个微任务.
  5. 第二个promise 已解析,因为这是同步代码,所以在解析后打印
  6. 执行第三个微任务,打印‘等待后’

Javascript相关问答推荐

如何将连续的十六进制字符串拆分为以空间分隔的十六进制块,每个十六进制块包含32个二元组?

Cookie中未保存会话数据

Angular material 拖放堆叠的牌副,悬停时自动展开&

如何在Vue 3中创建自定义 Select 组件,并将选项作为HTML而不是props 传递?

如何迭代叔父元素的子HTML元素

覆盖TypeScrip中的Lit-Element子类的属性类型

OpenAI转录API错误请求

触发异步函数后不能显示数据

AJAX POST在控制器中返回空(ASP.NET MVC)

令牌JWT未过期

Phaser3 preFX addGlow不支持zoom

自动滚动功能在当前图像左侧显示上一张图像的一部分

在GraphQL解析器中修改上下文值

按特定顺序将4个数组组合在一起,按ID分组

递增/递减按钮React.js/Redux

如何向内部有文本输入字段的HTML表添加行?

如何在加载页面时使锚定标记成为焦点

JavaScript -如何跳过某个字符(S)来打乱字符串中的字符

如何在函数组件中保留对计时器的引用

App Script如何读取通过云函数传递的表单对象