我使用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
答案 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