当Promise永远无法解决时会发生什么?

and*_*ais 10 javascript node.js promise

我使用es6 async await语法有这个非常令人困惑的代码片段.我期望发生的是该进程await永远挂起,因为从不调用resolve函数.然而,实际发生的是输出"start"然后进程退出而没有更多的输出.

const simple = async () => {
  console.log('start')
  await new Promise(resolve => {})
  console.log('done.')
}
simple()
Run Code Online (Sandbox Code Playgroud)

但是,下面的代码将打印"开始",等待1秒,然后打印"完成".

const simple = async () => {
  console.log('start')
  await new Promise(resolve => setTimeout(resolve, 1000))
  console.log('done.')
}
simple()
Run Code Online (Sandbox Code Playgroud)

我对这意味着什么(没有任何证据)的最接近的猜测是,当节点在等待承诺时,它会跟踪代码中发生的活动事件,当没有其他事情发生时,它就会退出.有人可以解释为什么代码退出这里?

赛跑 node v8.7.0

cae*_*say 7

是的,你对正在发生的事情有误解。

就像您说的那样,await由于您提到的原因,代码将永远不会在该调用之后继续,但这并不重要。

当您调用 时simple(),该方法本身会返回一个承诺 - 而您不是在等待该承诺。您的执行在调用后继续simple()并立即到达程序的末尾。

更详细地说,当没有更多的回调要处理时,nodejs 将退出。当你返回你违背的承诺时,你没有在 nodejs 队列中创建一个回调(就像你做一个 http 请求一样)。如果你做一些事情来让 nodejs 保持活力,你会看到它done永远不会被执行。

const simple = async () => {
  console.log('start')
  await new Promise(resolve => {})
  console.log('done.')
}
var promise = simple();

// keep the application alive forever to see what happens
function wait () {
    setTimeout(wait, 1000);
};
wait();
Run Code Online (Sandbox Code Playgroud)

如果有一个挂起的回调(由setTimeout,或从加载资源,或等待 http 响应创建),那么 nodejs 将不会退出。但是,在您的第一个示例中,您没有创建任何回调 - 您只是返回一个破碎的承诺。Nodejs 在那里没有看到任何“待处理”的东西,所以它退出了。

基本上在你的simple通话结束时,你没有更多的代码要执行,也没有任何待处理的东西(没有等待的回调),所以 nodejs 安全地知道没有其他事情要做。


Mar*_*yer 5

我最接近的猜测……它跟踪代码中正在发生的活动,当没有其他事件发生时,它只是退出。

这本质上是正确的。节点保留诸如计时器和网络请求之类的事物的参考计数。当您发出网络请求或其他异步请求时,请设置计时器等。Node会添加到此引用计数中。当次数/请求解析时,Node从计数中减去。

此计数是Node决定是否在事件循环结束时退出的方式。当您到达事件循环的结尾时,Node会查看此计数,如果计数为零,则退出。简单地做出一个承诺,不会增加引用数量,因为它不是异步请求。

[Node核心开发人员] Bert Belder对此进行了很好的讨论,这很有帮助:https : //www.youtube.com/watch?v= PNa9OMajw9w

  • 为什么第三行“done”不让进程保持活动状态?有更多的 JavaScript 需要执行!我理解空承诺不向队列添加回调,但为什么脚本的其余部分被忽略? (2认同)
  • @pinhead异步函数将await之后的代码转换为另一个函数,只有当给await的promise解析时,该函数才会运行。如果承诺永远无法解决,那么等待一些永远不会运行的代码有什么意义呢? (2认同)