猿问

Javascript:等待已解决的承诺

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


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


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');

})();

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


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


海绵宝宝撒
浏览 127回答 2
2回答

慕田峪4524236

这是一个不会冻结浏览器的替代演示(我认为这是我们试图展示的方式),它显示了与您最初的结论相反的行为:const p = new Promise((r) => r());p.then(() => {  (async() => {    console.log('a');    await p;    console.log('p');  })()  console.log('b');});在这种情况下,我们得到p一个已解决的承诺。然后我们启动一个等待它的异步函数。输出是:一个bp_IE 异步函数在点击已经解析的b时仍然返回控制权(并被记录)。只有在被记录之后,事件循环才可以自由地返回到随后被记录之后的执行。awaitpbawaitp这是标准行为吗?是的。该规范有效地将等待的表达式转换为then承诺的一部分,并在后续步骤的第 9 步和第 10 步中决定如何进行。如果 promise.[[PromiseState]] 处于待定状态,则a. 将 fulfillReaction 添加为列表的最后一个元素,即 promise.[[PromiseFulfillReactions]]。b. 附加 rejectReaction 作为 List 的最后一个元素,即 promise.[PromiseRejectReactions]]。否则如果 promise.[[PromiseState]] 被履行,a。然后让价值成为承诺。[[PromiseResult]]。b. 设 fulfillJob 为 NewPromiseReactionJob(fulfillReaction, value)c。执行 HostEnqueuePromiseJob(fulfillJob.[[Job]], fulfillJob.[[Realm]])。第 9 步表示如果它处于待处理状态,则将生成的添加到then承诺履行时要调用的事物列表中。第 10 步是您问题的核心——它说如果它已经完成,则将作业排入队列——即将它放在要回调的队列中。规范有效地说明了 anawait永远不应该同步返回。

陪伴而非守候

这是预期的行为。您在那里冻结了事件循环,因为承诺已经解决,下一个 await 运算符将在事件循环的同一迭代中等待并解决下一个承诺描述符。但这种行为可能是特定于平台的,具体取决于您实际使用的是哪种 promise 实现 - 本机或 shim。const promise= Promise.resolve();(async()=>{&nbsp; &nbsp; for(let i=0; i< 10000000; i++) {&nbsp; &nbsp; &nbsp; &nbsp; await promise;&nbsp; &nbsp; }&nbsp; &nbsp; console.log('end');})()setTimeout(()=> console.log('nextEventLoopTick'), 0);会输出如下:endnextEventLoopTick如您所见,async fn 将在 setTimeout 之前完全解析。因此,这表明异步函数是在同一个事件循环滴答上解析的。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答