DailyJS

Code Review: Oliver Caldwell's EventEmitter

Alex R. Young

Subscribe

@dailyjs

Facebook

Google+

events node code-review

Code Review: Oliver Caldwell's EventEmitter

Posted by Alex R. Young on .
Featured

events node code-review

Code Review: Oliver Caldwell's EventEmitter

Posted by Alex R. Young on .
*Code Review* is a series on DailyJS where I take a look at an open source project to see how it's built. Along the way we'll learn patterns and techniques by JavaScript masters. If you're looking for tips to write better apps, or just want to see how they're structured in established projects, then this is the tutorial series for you.

After a previous Code Review of
EventEmitter2 by hij1nx in Code Review: EventEmitter2, Oliver
Caldwell asked me to take a look at his
EventEmitter (GitHub: Wolfy87 / EventEmitter, License: MIT
and GPL).

This library places special focus on browser support, supporting all
major browsers and even IE 5+. A minimised version is also supplied to
further support client-side developers.

Usage

This EventEmitter implementation is used the same way as Node's:

// Initialise the EventEmitter
var ee = new EventEmitter();

function myListener() {
}

// Add the listener
ee.addListener('event', myListener);

// Emit the event
ee.emit('event');

// Remove the listener
ee.removeListener('event', myListener);

Structure

As with most browser-based libraries, I expected to see a self-executing
anonymous function. However, in this implementation the author has opted
to wrap everything in a regular function, declaring methods inside the
function's scope:

function EventEmitter() {
  var listeners = {},
      instance = this;

  instance.Event = function(type, listener, scope, once) {
  };

  instance.eachListener = function(type, callback) {
  };

  // Etc.
}

The Event class is used to encapsulate an event, and
instantiated Event objects are pushed onto arrays indexed
by type on listeners.

This style of encapsulation reminds me of how TJ Holowaychuk likes to
model his runtime objects (the Request and
Response classes in Express for
example). Also, it demonstrates high-level object oriented principles
without resorting to creating classical-OO-style classes in JavaScript.

Implementation

Like the other EventEmitter libraries, listeners are stored in an
Object. The newListener event has been
retained, which I thought shows good attention to detail. Most of the
core methods are extremely short, which I like to see. For example,
emit is implemented like this:

instance.emit = function(type, args) {
  instance.eachListener(type, function(currentListener) {
    return currentListener.fire(args);
  });

  // Return the instance to allow chaining
  return instance;
};

Extracting eachListener seems like a good idea. Rather than
having a lot of loops throughout the code, eachListener
gets reused by removeListener and emit, making
these methods more readable.

The code is also clearly commented, and the build process is included as
part of the Makefile.

Performance

The last time I looked at serious JavaScript loop benchmarks, optimised
for loops performed extremely well, which I suspect is why
EventEmitter and EventEmitter2 don't use the
callback-based iterators Oliver has used. He hasn't included benchmarks
so I can't easily say how well this implementation performs, but I did
find this code easier to follow than the other EventEmitters that I've
looked at.

Tests

Oliver has included QUnit tests, which do the job admirably:

test('Emitting events', function() {
  var ee = new EventEmitter();

  ee.addListener('emittingTest', function() {
    // Listener
    ok(true, 'First called');
  });

  ee.addListener('emittingTest', function() {
    // Another listener for the same event
    ok(true, 'Second called');
  });

  ee.addListener('differentEvent', function() {
    // Another listener for the same event
    ok(false, 'Wrong event called');
  });

  ee.emit('emittingTest');
});

I think these tests could benefit from being able to assert on how many
assertions are expected before the test completes, like
assert.expect in
nodeunit.

Conclusion

Yet another EventEmitter implementation, but this one still manages to
differentiate itself from the others I've looked at. I liked the way the
author has explored readability rather than purely performance; it
offers a hackable alternative that might suit certain projects. And the
code uses OO concepts without feeling too heavy handed.

Check it out yourselves on GitHub: Wolfy87 /
EventEmitter