node.js - 在非回调函数 : "interesting" results in node. 上调用 promisify() 为什么?

标签 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
    // 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')

这是一个启动 Node 服务器的简单自调用函数。 这很好。

现在...如果您取消注释“UNCOMMENT THIS”下的行, Node 将退出而不运行服务器。

我知道我在一个函数上使用 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...?')
})

只会打印“AH”!

最佳答案

Call promisify() on a non-callback function: “interesting” results in node. Why?

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

当您点击 await 并且 node.js 返回到事件循环时,没有任何东西让 node.js 继续运行,因此它退出。没有计时器或打开的套接字或任何保持 node.js 运行的类型,因此 node.js 自动退出检测逻辑说没有其他事情可做,所以它退出。

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

fp() 内部的真正异步操作将有某种套接字或计时器或保持进程运行的打开状态。但是因为你的是假的,那里没有任何东西,也没有任何东西可以让 node.js 运行。

如果在 f() 中放置 1 秒的 setTimeout(),您将看到进程在 1 秒后退出。因此,进程退出与 promise 无关。这与您已经回到事件循环这一事实有关,但您还没有开始任何可以保持 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() 处理程序公开 promise 并不能保证 node.js 运行。相反,需要一些事件的异步操作(计时器、网络套接字、监听服务器、正在进行的文件 I/O 操作等)来保持 node.js 运行。

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

If you change the function definition to something that actually calls a callback:

那是因为您使用了计时器,所以 node.js 在等待 promise 解决时实际上有一些事情要做。未调用 .unref() 的正在运行的计时器将阻止自动退出。

值得一读:How does a node.js process know when to stop?


仅供引用,您可以“关闭”或“绕过”node.js 自动退出逻辑,只需在您的启动代码中的任何位置添加:

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

这总是让 node.js 有事可做,因此它永远不会自动退出。然后,当您确实希望进程退出时,您可以调用 clearInterval(foreverInterval) 或使用 process.exit(0) 强制执行。

关于node.js - 在非回调函数 : "interesting" results in node. 上调用 promisify() 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49062977/

相关文章:

javascript - Node js检查文件是否被另一个进程使用

javascript - 如何获取从 Node js(express js 中间件)作为 json 响应发送的 Angular js 中的数据

javascript - 有没有办法保证 `Promise.all` 在内部 promise 的 `then` 链之后解析?

javascript - 在 promise 内返回 promise 时可能出现未处理的错误

c# - c# 中的异步单元测试设置

javascript - 我如何从 mongodb 数据库获取所有文档?

Node.js 和 Underscore.js

node.js - Mongoose $group 聚合未返回所需的结果

javascript - Promise.reject 消息是否应该包含在 Error 中?

.net - 在没有线程或异步设备的情况下,异步/等待模式是否无关紧要?