vitaly-t vitaly-t - 5 months ago 21
Node.js Question

Cannot remove dynamic event listeners

When using a regular function to bind to an event, I can remove it without problems. But when using a dynamic list of context functions, I cannot remove listeners for those.

Here's a simplified version of an entire test application:

'use strict';

var util = require('util');
var EventEmitter = require('events').EventEmitter;

function CustomEventEmitter() {
EventEmitter.call(this);
}

util.inherits(CustomEventEmitter, EventEmitter);

var obj = new CustomEventEmitter();

var onError, exists = false;

for (var i = 0; i < 20; i++) {

onError = function (err) {
console.log(err, i);
};

if (exists) {
obj.removeListener('error', onError);
exists = false;
}

obj.on('error', onError);
exists = true;
}


It will result in:

Warning: Possible EventEmitter memory leak detected. 11 error listeners added.
Use emitter.setMaxListeners() to increase limit


because the call to
removeListener
doesn't really remove the listener.

How one is supposed to remove dynamic listeners like that?

Answer

Yeah! When you do

var onError = function (err) {
    console.log(err, i);
};

that assigns a new function to the onError variable. Since you do that in between obj.on('error', onError); and obj.removeListener('error', onError);, the one you are trying to remove is not the same one you added. So nothing gets removed.

If you do this:

'use strict';

var util = require('util');
var EventEmitter = require('events').EventEmitter;

function CustomEventEmitter() {
    EventEmitter.call(this);
}

util.inherits(CustomEventEmitter, EventEmitter);

var obj = new CustomEventEmitter();

var exists = false;
var onError;

for (var i = 0; i < 20; i++) {
    if (exists) {
        obj.removeListener('error', onError);
        exists = false;
    }

    onError = function (err) {
        console.log(err, i);
    };

    obj.on('error', onError);
    exists = true;
}

it'll do what you want.

Comments