Javascript 当承诺永远无法兑现时会发生什么?

Javascript 当承诺永远无法兑现时会发生什么?,javascript,node.js,promise,Javascript,Node.js,Promise,我使用es6asyncawait语法编写了这段非常混乱的代码。我希望发生的是,进程永远挂在wait行上,因为从未调用resolve函数。然而,实际发生的是输出“start”,然后进程退出,不再输出 const simple = async () => { console.log('start') await new Promise(resolve => {}) console.log('done.') } simple() 但是,下面的代码将打印“开始”,等待1秒,然后

我使用es6
async
await
语法编写了这段非常混乱的代码。我希望发生的是,进程永远挂在
wait
行上,因为从未调用resolve函数。然而,实际发生的是输出“start”,然后进程退出,不再输出

const simple = async () => {
  console.log('start')
  await new Promise(resolve => {})
  console.log('done.')
}
simple()
但是,下面的代码将打印“开始”,等待1秒,然后打印“完成”

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


运行
节点v8.7.0

对,您对发生的事情有误解

就像你所说的,由于你提到的原因,在那次
等待
呼叫之后,代码将永远不会继续,但这并不重要

当您调用
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安全地知道没有其他事情要做

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

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

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


[Node core developer]Bert Belder对此进行了很好的讨论,这很有帮助:

你是对的,done永远不会被执行,但是如果你用
wait new promise(resolve=>setTimeout(resolve,1000))
替换
wait
行,那么这段代码可以等待正在执行的承诺,代码随后将输出“done”,而不需要任何处理程序。我已更新我的问题以显示this@andykais对确切地我就是这么说的。
setTimeout
方法创建nodejs正在查找的回调。如果有任何挂起的回调,nodejs将不会退出。您的第一个示例不会创建任何挂起的回调,它只是返回一个承诺。感谢您的讨论非常有见地!关于
ref++
ref--
跟踪每件事并承诺不添加计数的观点非常清楚地说明了为什么这个程序存在,为什么第三行
done
不能保持进程活动?还有更多的JavaScript需要执行!我理解不向队列添加回调的空洞承诺,但为什么脚本的其余部分被忽略了?我发现还有一件事值得一提,以便更容易理解这里发生了什么。由于它是一个
异步
/
等待
函数,因此它不同于常规函数,后者总是运行到完成。如果将
simple
重写为不使用
async
/
await
,则
await
语句后面的代码必须放在
回调函数中。由于不调用
resolve()
,因此该代码永远不会执行,因此控制台不会打印“完成”。然而,承诺的主体是立即执行的,因为它是空的,所以程序没有什么可执行的了!说得好!如果不使用
async
/
await
语法来考虑这一点,那么代码停止执行的原因会更加明显。下面可以找到一个很好的解释:
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();