【问题标题】:Non existing property: EventEmitter memory error instead of proper error message不存在的属性:EventEmitter 内存错误而不是正确的错误消息
【发布时间】:2017-12-21 13:56:37
【问题描述】:

在基于 NodeJS 6.10.2/SailsJS 0.12.13 的 JavaScript 应用程序中,几个月以来我遇到了一个奇怪的错误行为。

在 Sails 控制器中,我尝试检索文字对象的属性:

console.log(someObject.someProperty);
console.log("I am still here!");

但是,就我而言,someObject 是未定义的。所以,我希望得到一个错误,比如“无法读取未定义的属性 someProperty”。 - 然后要么 Node.js 完全停止,要么继续运行代码(使用下一个 console.log)。

相反,代码在该点停止执行,我收到一个奇怪的警告:“(node:4822) 警告:检测到可能的 EventEmitter 内存泄漏。添加了 11 个关闭侦听器。使用emitter.setMaxListeners() 增加限制。”然而,这个错误发生的频率是不可预测的。一些东西只有一次,一些东西紧接着大约 20 次。

我发现它与是否已经有回应的问题有某种联系。考虑以下几点:

mySailsControllerFunction: function(req, res) {
    console.log(someObject.someProperty);
    console.log("I am still here!");
    res.json({"foo":"dahoo"});
   }

这将导致Sending 500 ("Server Error") response: ReferenceError: someObject is not defined - 正是我所期望的。

但是,现在我首先发送一些响应,然后尝试访问我不存在的属性,将代码变成:

mySailsControllerFunction: function(req, res) {
        res.json({"foo":"dahoo"});
        setTimeout(function () {
          console.log("Yeah!");
          console.log(someObject.someProperty);
          console.log("I am still here!");
       },1000);
}

然后我常常一无所获:“是的!”显示,但之后什么都没有。事件侦听器错误有时存在,有时不存在。很奇怪。

此外,奇怪的是,这个问题似乎与 Sails 开始以来经过的时间有关。我将您在上面看到的代码放在 Sails 控制器函数中,该函数在客户端重新连接后立即调用。然后我玩弄了超时值,重新启动了 Sails 服务器几次。结果:如果我将超时设置为 1 秒,在 5 次测试中的 4 次中,我将获得正确的错误行为。 10 秒内大约是 50%,30 秒内错误将始终被忽略,没有任何控制台输出。

但是,如果我将测试代码放在 Sails 控制器之外,我总是会得到 Node.js 的正确错误行为。所以,我很确定这是 Sails 的错误行为,而不是 Node。

【问题讨论】:

  • 如果没有更多上下文,很难判断发生了什么。例如,如果该代码在 Promise 链中运行,则可能是由于编码错误,错误被吞没了。这与一些奇怪的错误处理相结合(“添加了 11 个关闭侦听器” 看起来很奇怪)。
  • 在上面查看我的编辑
  • 更改 eventEmitter 限制后观察到什么行为?
  • 老实说,我不知道具体在哪里做。我自己没有在这里设置任何事件监听器。这是由 Sails 以某种方式完成的。

标签: javascript node.js sails.js


【解决方案1】:

免责声明:我不知道 Sails。所以它可能相关也可能不相关,但我的回答可能会提供线索。

来自 Sails 文档: http://sailsjs.com/documentation/reference/response-res/res-json

这个方法是终端的,也就是说一般是最后一行代码 您的应用程序应该针对给定的请求运行(因此建议使用 在这些文档中返回)。

因此,当您使用res.json({"foo":"dahoo"}); 时,Sails 可能会将响应发送回客户端,关闭调用序列,如果它使用 Promises 或其他异步机制,可能会“吞下”更多代码,同样在上面的评论中建议。这可能是 Sails 中的内部编码,因此从外部无法立即看出为什么您的第二个代码块特别不起作用。

所以你应该坚持第一种模式:首先访问你的属性,并将res.json()放在控制器函数的末尾。

【讨论】:

  • 谢谢。但是,我不相信。引用的文档 sn-p 中的关键字是request:据我了解,在您完成请求后,您可以对与请求无关的所有内容做任何您想做的事情。如果没有错误,那么我的所有代码都按预期工作。问题是控制台上没有记录/显示错误。此外,问题以某种方式与服务器正常运行时间有关的奇怪现象也不能用res.json之后的所有内容都没有执行的假设来解释。
  • 我不同意。在您响应您的 (http) 请求者后,它通常会以任何语言调用错误来访问属性、数据和函数线程。想一想——http 客户端请求资源,后端进行一些旋转,然后返回响应。从概念上讲,这关闭了循环,调用被视为终止。我建议重新访问您的代码 - 为什么在您回复客户后需要访问任何内容?如果你真的需要它,你应该产生一些异步调用来处理数据,但让客户端尽快终止调用。
  • “您可以对与请求无关的所有内容做任何您想做的事情” - 首先,如果呼叫是由客户端发起的,它怎么可能与请求无关。其次,您将让客户端等待您的后端进程,这被认为是反模式。第三,就像上面的评论一样,是的,在请求之后做任何你想做的事情,但如果它与请求无关,它确实应该不理会请求 - 终止 http 响应,但处理异步 - 解耦你的代码。但是文档很清楚 - res.json() 应该是请求中的最后一个。
  • 选项是 redis、消息传递、微服务....任何将后端进程与 http 调用解耦的方法
  • 最后一句话——您使用的是 Sails 控制器。控制器在概念上是处理请求的 MVC 模式的一部分。使用res.json(),您是在说“我完成了 HTTP 请求”,它在 HTTP 上下文中运行的 MVC 控制器领域中运行。因此,您实际上是在说我完成了,然后框架(Sails)接管,终止调用,然后您的代码假装做其他事情。所以在 HTTP 上下文中,无论你做什么都应该在 res.json() 之前,如果你需要离开 HTTP 上下文,就异步执行。
【解决方案2】:

供参考:我终于解决了这个问题。 不知何故隐藏在代码中,定义了进程退出处理程序:

 process.on('exit', myErrorFunction.bind());
 process.on('SIGINT', myErrorFunction.bind());
 process.on('uncaughtException', myErrorFunction.bind());

问题是:这些行所在的函数绑定到一个 cronjob。因此,每次执行 cronjob 时,都会注册新的处理程序。所以,我上面的假设(响应之前与响应之后)是错误的:事实上,在第一次执行 cronjob 之前一切正常。从那以后,就没有了。最终,警告被触发(正确!)。

如果没有这个答案,我永远不会发现:Make node show stack trace after EventEmitter warning 您必须添加一行代码才能获取堆栈跟踪:

process.on('warning', e => console.warn(e.stack));

另外,说到堆栈跟踪:在 Sails serverError 响应(api/api/responses/serverError.js)中,这样访问它很方便:

module.exports = function serverError (data, options) {
  console.log(data.stack);
  /* ... */
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 2010-12-27
    • 2019-02-08
    • 2018-04-10
    • 2022-11-20
    • 1970-01-01
    • 2020-05-04
    相关资源
    最近更新 更多