readline: fix close event of readline.Interface()

Not removing 'end' listeners for input and output on the 'close' event
resulted in an EventEmitter related memory leak.

This issue also might be reproduced at:
https://github.com/npm/npm/issues/5203

Signed-off-by: Trevor Norris <trev.norris@gmail.com>
This commit is contained in:
Yazhong Liu 2014-05-08 00:05:39 +08:00 committed by Trevor Norris
parent 0f503cf0de
commit e1aa066fe1
2 changed files with 30 additions and 5 deletions

View File

@ -97,6 +97,13 @@ function Interface(input, output, completer, terminal) {
self.close();
}
function ontermend() {
if (util.isString(self.line) && self.line.length > 0) {
self.emit('line', self.line);
}
self.close();
}
function onkeypress(s, key) {
self._ttyWrite(s, key);
}
@ -121,11 +128,7 @@ function Interface(input, output, completer, terminal) {
// input usually refers to stdin
input.on('keypress', onkeypress);
input.on('end', function inputEnd() {
if (util.isString(self.line) && self.line.length > 0)
self.emit('line', self.line);
self.close();
});
input.on('end', ontermend);
// Current line
this.line = '';
@ -142,6 +145,7 @@ function Interface(input, output, completer, terminal) {
output.on('resize', onresize);
self.once('close', function() {
input.removeListener('keypress', onkeypress);
input.removeListener('end', ontermend);
output.removeListener('resize', onresize);
});
}

View File

@ -35,6 +35,14 @@ FakeInput.prototype.pause = function() {};
FakeInput.prototype.write = function() {};
FakeInput.prototype.end = function() {};
function isWarned(emitter) {
for (var name in emitter) {
var listeners = emitter[name];
if (listeners.warned) return true;
}
return false;
}
[ true, false ].forEach(function(terminal) {
var fi;
var rli;
@ -262,4 +270,17 @@ FakeInput.prototype.end = function() {};
assert.equal(readline.getStringWidth('> '), 2);
assert.deepEqual(fi.listeners(terminal ? 'keypress' : 'data'), []);
// check EventEmitter memory leak
for (var i=0; i<12; i++) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.close();
assert.equal(isWarned(process.stdin._events), false);
assert.equal(isWarned(process.stdout._events), false);
}
});