Skip to content

Commit

Permalink
events: don't call once twice
Browse files Browse the repository at this point in the history
Emitting an event within a `EventEmitter#once` callback of the same
event name will cause subsequent `EventEmitter#once` listeners of the
same name to be called multiple times.

    var emitter = new EventEmitter();

    emitter.once('e', function() {
      emitter.emit('e');
      console.log(1);
    });

    emitter.once('e', function() {
      console.log(2);
    });

    emitter.emit('e');

    // Output
    // 2
    // 1
    // 2

Fix the issue, by calling the listener method only if it was not
already called.
  • Loading branch information
timrwood authored and indutny committed Nov 12, 2013
1 parent ac9cf00 commit c9d93f3
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
8 changes: 7 additions & 1 deletion lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,15 @@ EventEmitter.prototype.once = function(type, listener) {
if (typeof listener !== 'function')
throw TypeError('listener must be a function');

var fired = false;

function g() {
this.removeListener(type, g);
listener.apply(this, arguments);

if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}

g.listener = listener;
Expand Down
16 changes: 16 additions & 0 deletions test/simple/test-event-emitter-once.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,19 @@ process.on('exit', function() {
assert.equal(1, times_hello_emited);
});

var times_recurse_emitted = 0;

e.once('e', function() {
e.emit('e');
times_recurse_emitted++;
});

e.once('e', function() {
times_recurse_emitted++;
});

e.emit('e');

process.on('exit', function() {
assert.equal(2, times_recurse_emitted);
});

0 comments on commit c9d93f3

Please sign in to comment.