Reputation: 6020
I've been trying to resolve a bug in a nodejs application, and have narrowed it down to the way I've implemented event emitters. The application is an express.js app, has uses classes. There's some critical aspect of NodeJS that I must be missing, around memory usage and class / object lifecycles. I was hoping someone could point out why what I'm doing is not working as expected.
Here's the code:
// ServiceWrapper.js:
var events = require('events');
var ServiceClient = function(opts) {
this.foobar = "";
this.opts = opts;
this.hasFoo = false, this.hasBar = false;
}
ServiceClient.prototype = new events.EventEmitter();
ServiceClient.prototype.getFoo = function() {
var self = this;
self.hasFoo = true;
self.foobar += "foo";
self.emit('done','foo');
}
ServiceClient.prototype.getBar = function() {
var self = this;
self.hasBar = true;
self.foobar += "bar";
self.emit('done','bar');
}
var ServiceWrapper = function(){}
ServiceWrapper.prototype.getResponse = function(options, callback) {
var servClient = new ServiceClient({});
servClient.on('done', function(what) {
if (servClient.hasFoo && servClient.hasBar) {
console.log("foo && bar")
callback(servClient.foobar);
}
else {
console.log("Don't have everything: " + servClient.foobar);
}
});
servClient.getFoo();
servClient.getBar();
}
module.exports = ServiceWrapper
And then in my express app:
var ServiceWrapper = require('ServiceWrapper');
app.get('/serviceReponse', function(req,res) {
var servWrapper = new ServiceWrapper();
servWrapper.getResponse(function(ret) {
res.end(ret);
});
});
The behaviour on the web app works as expected: response is set to "foobar". However, looking at the logs, it looks like there's a memory leak - multiple instances of servWrapper
. After starting the application, the first request generates:
Don't have everything: foo
foo && bar
However, if I refresh the page, I see this:
foo && bar
Don't have everything: foo
foo && bar
foo && bar
And with every refresh, the listener detects multiple 'done' events - foo && bar
outputs keeps growing (assuming there's more and more instances of ServiceWrapper that persist in memory).
Why does this happen? (I expect to see the output that I get on the first request from every request).
Upvotes: 1
Views: 258
Reputation: 6020
Thanks to the guys on #node.js on freenode for assisting with this:
sure, but every time you attach listeners, you're attaching them to the same emitter since you didn't localize the prototype's state to your instance, the prototype methods act upon the state of the prototype object. I believe you can fix it by simply doing EventEmitter.call(this) in the constructor
See the following link for more info:
Upvotes: 2