为什么 `async/await` 在我的情况下不起作用?

Why `async/await` doesn't work in my case?

我读到了 async/await,但我有一个关键问题。 首先,我解释了一个旧示例以显示我的问题的基础,然后我提出了我的确切问题。

人尽皆知:

console.log('1');
console.log('2');
console.log('3'); // Ex: 123

这很简单,但在下面的例子中:

console.log('1');
setTimeout(()=>{
    console.log('2');
},0);
console.log('3'); // Ex: 132

也很简单,setTimeout函数就是asynchronousJavaScript从它跳转,解析运行它的函数,所以我们看到213.

之后

但是,现在我读 async/await 并且写了一个这样的函数:

(async function test() {
    console.log('1');
    await setTimeout(()=>{
        console.log('2');
    },0);
    console.log('3');
})(); // Ex: 132

导出也是132,为什么?这是我的问题,为什么 3 运行 在 2 之前?我预计因为 async/await1 JavaScript 等待 2 然后写 3。为什么 132?

您可以 await 使用 returns Promise 的功能。 setTimeout 没有 returns Promise。所以在这种情况下 awaitsetTimeout 之前使用是没有意义的。

您可以将 setTimeout 包装到 Promise 中并在 setTimeout 函数中调用 resolve。

(async function test() {
    console.log('1');
    await new Promise((resolve, reject) => { 
         setTimeout(() => {
            console.log('2');
            resolve(); // also can pass a parameter here to get it via await.
         },0);
    });
    console.log('3');
})();

因为 setTimeout 没有 return 承诺。 await x 只有在 x 是一个承诺时才会等待;如果 x 不是一个承诺,它会(有效地)包含在一个承诺中,就好像您有 await Promise.resolve(x) 一样。这意味着它后面的代码将 运行 异步但尽快。*

如果您想要 setTimeout 的承诺版本,请参阅 this question's answers。但即便如此,您的 test 函数也不会使用回调,而您只是等待启用承诺的超时:

function later(delay) {
    return new Promise(function(resolve) {
        setTimeout(resolve, delay);
    });
}

async function test() {
  console.log("1");
  await later(10);
  console.log("2");
  console.log("3");
}

test().catch(e => console.error(e));
console.log("After the call (just to prove it does wait for the timeout after 1 and before 2");


* 在浏览器上,这保证在同一任务期间安排的 setTimeout(..., 0) 之前,因为在任务期间安排的 promise 回调发生在该任务结束之后,在从中拾取下一个任务之前队列(即使下一个任务是在 promise 回调之前安排的)。 this question's answers.

中的更多信息("macrotasks" 和 "microtasks")

await 只有当传递给它的值是 Promise 时才会挂起。在你的情况下,setTimeout returns a Number 所以 await 不会等待它。

正确的代码如下:

async function test() {
    console.log('1');
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('2');
            resolve()
        }, 0);
    });
    console.log('3');
}