Javascript:等待解决的承诺

Poy*_*man 6 javascript promise async-await

我想知道,如果等待已解决的承诺,将导致同步代码执行或可能导致异步代码执行。

我制作了这个小片段来检查浏览器:

const promise = new Promise((resolve) => {
  console.log('exec promise');
  setTimeout(() => {
    console.log('executed promise');
    resolve();
  }, 1000);
});

(async () => {
  console.log('start');
  for (let i = 0; i < 1e8; i += 1) {
    await promise;
  }
  console.log('end');
})();
Run Code Online (Sandbox Code Playgroud)

看起来浏览器使其同步(考虑到屏幕冻结)。

但是......这是由于浏览器特定的实现吗?还是设计使然?

Jam*_*rpe 5

这是一个替代演示,它不会冻结浏览器(我认为这妨碍了我们想要展示的内容),并且显示了与您最初的结论相反的行为:

const p = new Promise((r) => r());

p.then(() => {

  (async() => {
    console.log('a');
    await p;
    console.log('p');
  })()
  console.log('b');

});
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们得到了p,一个已解决的承诺。然后我们启动一个等待它的异步函数。输出是:

ab
p

即,当异步函数击中已解决的b时,它仍然返回控制权(并被记录)。只有在被记录之后,事件循环才可以在随后被记录之后返回执行。awaitpbawaitp

这是标准行为吗?是的。

规范有效地将等待的表达式转变为thenPromise 的一部分,并在后续步骤的步骤 9 和 10 中决定如何继续。

  1. 如果 Promise.[[PromiseState]] 处于待处理状态,则
    a. 将 fillReaction 附加为 List 的最后一个元素,即 Promise.[[PromiseFulfillReactions]]。
    b. 将rejectReaction 附加为List 的最后一个元素,即promise.[PromiseRejectReactions]]。
  2. 否则,如果 Promise.[[PromiseState]] 得到满足,
    则 a. 然后设值为promise.[[PromiseResult]]。
    b. 令fulfillJob 为NewPromiseReactionJob(fulfillReaction, value)
    c.执行 HostEnqueuePromiseJob(fulfillJob.[[Job]],fulfillJob.[[Realm]])。

步骤 9 表示如果它处于待处理状态,则将生成的内容添加then到承诺完成时要调用的事物列表中。

步骤 10 触及您问题的核心 - 它表示如果已经完成,则将作业排队 - 即将其放置在要回调的事物队列中。

该规范实际上表明 anawait永远不应该同步返回。