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

cis*_*cis 11 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!");
Run Code Online (Sandbox Code Playgroud)

但是,在我的情况下someObject是未定义的.所以,我希望得到一个错误,比如'无法读取属性someProperty of undefined'.- 然后Node.js完全停止或代码继续(下一个console.log).

相反,代码只是在那时停止执行,我得到一个奇怪的警告:"(节点:4822)警告:检测到可能的EventEmitter内存泄漏.添加了11个关闭的侦听器.使用emitter.setMaxListeners()来增加限制." 但是,这种错误发生的频率是不可预测的.有些人只有一次,有些人约20次.

我发现的是,它在某种程度上与是否已经有回应的问题有关.考虑以下:

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

这将导致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);
}
Run Code Online (Sandbox Code Playgroud)

然后我经常一无所获:'是啊!' 显示,但之后什么都没有.有时会出现事件侦听器错误,有时不会出现错误.很奇怪.

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

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

cis*_*cis 0

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

 process.on('exit', myErrorFunction.bind());
 process.on('SIGINT', myErrorFunction.bind());
 process.on('uncaughtException', myErrorFunction.bind());
Run Code Online (Sandbox Code Playgroud)

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

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

process.on('warning', e => console.warn(e.stack));
Run Code Online (Sandbox Code Playgroud)

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

module.exports = function serverError (data, options) {
  console.log(data.stack);
  /* ... */
};
Run Code Online (Sandbox Code Playgroud)