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

时间:2017-10-27 03:06:21

标签: javascript node.js promise

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

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

然而,下面的代码将打印“开始”,等待1秒,然后打印“完成”。

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

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

正在运行node v8.7.0

2 个答案:

答案 0 :(得分:4)

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

就像你说的那样,代码永远不会在你提到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();

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

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

答案 1 :(得分:4)

  

我最接近的猜测......它跟踪代码中发生的活动事件,当没有其他事情发生时,它就会退出。

这基本上是正确的。节点保留计时器和网络请求之类的引用计数。当您创建网络或其他异步请求时,请设置计时器等。节点会添加此引用计数。当时间/请求解析节点从计数中减去时。

此计数是Node如何决定是否在事件循环结束时退出。当你到达事件循环结束时,Node会查看此计数,如果它为零,则退出。简单地做出承诺,不会添加引用计数,因为它不是异步请求。

[节点核心开发人员] Bert Belder对这方面的一些讨论很有帮助:https://www.youtube.com/watch?v=PNa9OMajw9w