不存在的属性:EventEmitter内存错误而不是正确的错误消息

时间:2017-07-17 06:27:37

标签: javascript node.js sails.js

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

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

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

但是,在我的情况下,someObject未定义。因此,我希望得到一个错误,例如'无法读取某些属性未定义的属性。' - 然后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服务器。结果:如果我将超时设置为1s,在5次测试中的4次中,我将得到正确的错误行为。对于10秒,它大约是50%,对于30秒,在没有任何控制台输出的情况下总是会忽略错误。

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

2 个答案:

答案 0 :(得分:2)

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

从Sails文档中: http://sailsjs.com/documentation/reference/response-res/res-json

  

此方法是终端,这意味着它通常是最后一行代码   你的应用程序应该针对给定的请求运行(因此建议使用   返回这些文档)。

因此,当你使用res.json({"foo":"dahoo"});时,Sails可能会将响应发送回客户端,关闭调用序列,如果它使用Promises或其他一些异步机制,可能会“吞下”更多的代码,正如上述评论中所述。这可能是Sails中的内部编码,所以从外面看并不是很明显为什么你的第二个代码块特别不起作用。

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

答案 1 :(得分:0)

供参考:我终于解决了这个问题。 在某种程度上隐藏在代码中,处理定义的退出处理程序:

 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);
  /* ... */
};