Node.js 对非回调函数调用promisify();“有趣”;结果在节点中。为什么?

Node.js 对非回调函数调用promisify();“有趣”;结果在节点中。为什么?,node.js,promise,async-await,es6-promise,Node.js,Promise,Async Await,Es6 Promise,我在node的promisify()函数中发现了一个奇怪的行为,我无法理解它为什么要这样做 考虑以下脚本: #!/usr/bin/env node /** * Module dependencies. */ var http = require('http') var promisify = require('util').promisify ;(async () => { try { // UNCOMMENT THIS, AND NODE WILL QUIT

我在node的promisify()函数中发现了一个奇怪的行为,我无法理解它为什么要这样做

考虑以下脚本:

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var http = require('http')

var promisify = require('util').promisify

;(async () => {
  try {

    // UNCOMMENT THIS, AND NODE WILL QUIT
    // var f = function () { return 'Straight value' }
    // var fP = promisify(f)
    // await fP()

    /**
     * Create HTTP server.
     */
    var server = http.createServer()

    /**
     * Listen on provided port, on all network interfaces.
     */

    server.listen(3000)
    server.on('error', (e) => { console.log('Error:', e); process.exit() })
    server.on('listening', () => { console.log('Listening') })
  } catch (e) {
    console.log('ERROR:', e)
  }
})()

console.log('OUT OF THE ASYNC FUNCTION')
它是一个简单的自调用函数,用于启动节点服务器。 那很好

现在。。。如果您取消对“uncomment THIS”下的行的注释,则节点将在不运行服务器的情况下退出

我知道我正在对一个函数使用promisify(),该函数不调用回调,而是返回一个值。所以,我知道这本身就是一个问题

然而。。。为什么node刚刚退出

这真的很难调试——特别是当您有比一个小脚本更复杂的东西时

如果将函数定义更改为实际调用回调的内容:

var f = function (cb) { setTimeout( () => { return cb( null, 'Straight value') }, 2000) }
一切正常

更新

巨大的简化:

function f () {
  return new Promise(resolve => {
    console.log('AH')
  })
}

f().then(() => {
  console.log('Will this happen...?')
})
只会打印“啊”

对非回调函数调用promisify():节点中的“有趣”结果。为什么?

因为您允许node.js进入事件循环,而无需做任何事情。由于没有实时的异步操作,也没有更多的代码可以运行,node.js意识到没有其他事情可以做,也没有其他任何事情可以运行,所以它退出了

当您点击
wait
并且node.js返回到事件循环时,没有任何东西可以保持node.js运行,因此它会退出。node.js没有计时器、开放式套接字或其他任何类型的东西可以保持运行,因此node.js自动退出检测逻辑表示,没有其他方法可以让它退出

由于node.js是一个事件驱动系统,如果您的代码返回到事件循环,并且没有任何类型的异步操作(打开套接字、侦听服务器、计时器、文件I/O操作、其他硬件侦听器等),然后,在事件队列中没有任何可以插入任何事件的运行,并且队列当前为空。因此,node.js意识到,在这个应用程序中永远不可能再运行任何代码,所以它会退出。这是node.js中内置的自动行为

fp()
中真正的异步操作将具有某种套接字、计时器或保持进程运行的打开的东西。但是因为你的是假的,所以没有任何东西可以让node.js继续运行

如果将
setTimeout()
放置在
f()
内1秒,您将看到进程退出发生在1秒后。因此,流程退出与承诺无关。这与您已经返回到事件循环这一事实有关,但是您还没有启动任何可以保持node.js运行的东西

或者,如果在异步函数的顶部放置一个
setInterval()
,您同样会发现进程不会退出


所以,如果你这样做,同样会发生这种情况:

var f = function () { return 'Straight value' }
var fP = promisify(f);
fP().then(() => {
    // start your server here
});
或者这个:

function f() {
    return new Promise(resolve => {
       // do nothing here
    });
}

f().then(() => {
    // start your server here
});
问题不在于
promisify()
操作。这是因为您正在等待一个不存在的异步操作,因此node.js无事可做,它注意到无事可做,因此自动退出。使用
.then()
处理程序的开放承诺并不能保证node.js的运行。相反,需要一些活动的异步操作(计时器、网络套接字、侦听服务器、正在进行的文件I/O操作等)来保持node.js运行

在这种特殊情况下,node.js基本上是正确的。你的承诺永远不会兑现,其他任何东西都不会排队运行,因此你的服务器永远不会启动,应用程序中的其他代码也永远不会运行,因此继续运行实际上是没有用的。没有什么可以做的,也没有办法让您的代码实际执行任何其他操作

如果将函数定义更改为实际调用回调的内容:

var f = function (cb) { setTimeout( () => { return cb( null, 'Straight value') }, 2000) }
这是因为您使用了一个计时器,所以node.js在等待承诺解决时实际上有一些事情要做。未调用
.unref()
的正在运行的计时器将阻止自动退出

值得一读:


仅供参考,只需在启动代码中的任意位置添加以下内容,即可“关闭”或“绕过”node.js自动退出逻辑:

// timer that fires once per day
let foreverInterval = setInterval(() => {
    // do nothing
}, 1000 * 60 * 60 * 24);

这总是让node.js做一些事情,所以它永远不会自动退出。然后,当您确实希望流程退出时,您可以调用
clearInterval(foreverInterval)
或使用
process.exit(0)

Hmmm>强制执行操作。我假设在一段时间的空事件循环(等待一个永远不会解决的承诺)之后,节点就继续移动。因为你没有别的东西在听输入,它就像一个脚本一样,只是关闭了?这是我的理论,但它没有解释为什么使用一个合适的回调函数,它会工作@劳埃德,读以“我知道”开头的部分他知道这个问题的重点是确定node可能存在的问题,并且——在将来——让开发人员更容易确定这样的问题。事实上,这不应该发生。在我在node中打开一个合适的bug之前,我想知道更广泛的SO社区对此有何想法(这可能会让我自己难堪!)@Merc-我不确定你对该代码的要求是什么?您永远不会解决您的承诺,因此将永远不会调用
.then()
处理程序。类似地,没有使用该代码实际调度的异步操作,因此node.js将退出。仅仅创建承诺并不能阻止node.js退出。您需要一个实时异步操作来阻止node.js退出。代码是错误的粘贴--抱歉。请看我对这个问题的更新。你是绝对正确的——我从来没有想到过!!!所以更新代码到底发生了什么
f()
显然会运行,并返回一个承诺。承诺回调中的代码将被执行(因此您会看到“AH”)。然后。。。当然,当然