On+On+On Everywhere I want to be

8Oct/130

Properly extending EventEmitter in node.js

A particularly powerful pattern in node.js is that of EventEmitters. One of the core architectural pieces of Donna's machinery, Qred, makes use of the EventEmitter pattern to allow other parts of the system to learn when a job, or a particular job, has been completed.

JavaScript is certainly not known for its intuitive syntax and idioms when it comes to extending objects and setting up prototype chains. While there are some fairly well-defined best practices, it's easy to become careless and do the wrong thing. I found myself recently bitten when playing with making objects that emit events in node.js because I didn't pay close attention to how I was setting up my prototype chains.

To create a JavaScript object that is based on another object, you have to set up its prototype chain. This involves putting some kind of object into the prototype field of your object. So, the question then becomes: what do we put in this field?

Well, you want your object's prototype to be an object that has a prototype which is the object you're trying to extend the functionality of. One of the ways we first learn to do something like this in JavaScript is with the new keyword. However, more modern versions of JavaScript have introduced newer ways to create objects based on a prototype. So we also have Object.create(). Furthermore, node.js provides a utility function in the util module called inherits. However, under the hood, it's based on Object.create, and also sets up some constructor and superclass information.

So, what's the difference in setting your prototype using new vs. using Object.create? It's subtle, but important. When you use new, a new object based on the prototype of the specified object is created, and the initialization code is run. When you use Object.create, the new object is created with the prototype chain set up, but the initialization code is not run.

This is an important distinction in the case of setting up EventEmitter functionality in node.js. When you call new EventEmitter some internal state is initialized, but only if it did not exist yet. This means, if you initialize your custom EventEmitter prototype chain using new, all subsequent instances of your custom emitter will share some internal structures. One of those structures is a list of events to be emitted, contained in the _events field of the object. The code of interest in the EventEmitter initialization looks like this:

this._events = this._events || {};

If this initialization code is run, then any objects created further down the initialization chain will see the already-created _events object, and not create a new one. So now a single _event queue is shared amongst all of the objects. This means that if you create multiple instances of your custom EventEmitter, all of the instances with registered event listeners will fire these listener for any event emitted from any instance. This is most likely not the behavior you are looking for.

To exhibit the difference, let's look at a small code example. We'll create two custom EventEmitter objects, one that sets up its prototype chain using new EventEmitter and one that sets up its prototype chain using Object.create(EventEmitter.prototype) via the util.inherits helper function.

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

function GoodEmitter() {
    EventEmitter.call(this);
}
util.inherits(GoodEmitter, EventEmitter);

function BadEmitter() {
    EventEmitter.call(this);
}
BadEmitter.prototype = new EventEmitter();

var good1 = new GoodEmitter();
good1.on('ev', function(msg) { console.log("Good Instance 1: "+msg); });
var good2 = new GoodEmitter();
good2.on('ev', function(msg) { console.log("Good Instance 2: "+msg); });
good1.emit('ev', 'GoodEmitter: Emitting from Instance 1');

var bad1 = new BadEmitter();
bad1.on('ev', function(msg) { console.log("Bad Instance 1: "+msg); });
var bad2 = new BadEmitter();
bad2.on('ev', function(msg) { console.log("Bad Instance 2: "+msg); });
bad1.emit('ev', 'BadEmitter: Emitting from Instance 1');

If you run this code using node.js, you will see:

$ node ee.js
Good Instance 1: GoodEmitter: Emitting from Instance 1
Bad Instance 1: BadEmitter: Emitting from Instance 1
Bad Instance 2: BadEmitter: Emitting from Instance 1

So we see quite clearly: we have both instances of the bad emitter object responding to an event published by just one of the bad emitter instances. The same pattern with the good emitter behaves as expected, only firing listeners registered on the object that emitted the event.

There may be cases where one could argue for the behavior that I have called the "bad" emitter case, but in the particular use case I had, it was undesirable behavior.

Filed under: Hacking No Comments
27Feb/120

The American Nightmare

This fascinating, well-written first-hand account of working in a US shipping warehouse is one of the most depressing things I've read in a while. I often see articles discussing the (admittedly worse than this) conditions of factories overseas. But as we see in this experiment, the downward spiral of wanting cheaper goods touches a number of Americans in a similar way. And fittingly so, as these jobs are the distribution-side counterpart to the manufacturing hell that we've already heard so much about.

The arguments along the lines of "you should be happy that you have a job" are sickening. I've always felt acutely disappointed by that class of arguments, certainly more so when it's used to abuse and profit from other human beings. Perhaps my whiny, idealistic opinion makes me a liberal soft-ass, but I think that individual happiness *should* be top-of-the-list goal, and considered a sign of a healthy, successful nation. If the only point of living is to subsist with a meager quality of life with the hopes of further propagating your genes--and thus the human race--then suddenly nihilism doesn't seem like so much like the philosophy of madmen as it once did to me.

It doesn't seem to me that it needs to be this way (indeed, the author says the same thing). I've heard a number of variants of pithy quotes along the lines of "The last 5% of the work takes 95% of the effort." -- and I think that it applies here, as well: the last 5% of the efficiency takes 95% of the quality of life from the employees.

It's not clear to me what the proper direction for improvement is. I have no doubt that pieces like this one raising awareness of such conditions is a very large step in the right direction.

The quote that sums it up for me:

I feel genuinely sorry for any child I might have who ever asks me for anything for Christmas, only to be informed that every time a "Place Order" button rings, a poor person takes four Advil and gets told they suck at their job.
Filed under: Opinion No Comments
27Feb/101

Gliss for Palm Pre and Pixi fixed for webOS 1.4

After a 3-day delay waiting for update approval from Palm, Gliss and Glissito are finally fixed to work in webOS 1.4, so make sure you update!

I wasn't expecting changes that would affect my game, which is why this change was last-minute.

My apologies for the few days of a non-working game.

Tagged as: , , 1 Comment
18Feb/100

WTF, WTFJS?

My co-worker Jason Ostrander recently tipped me off about a new blog that's recently appeared, called wtfjs.com. I'm all about geek humor, so I ran quickly to check it out.

My initial reaction was one of complete annoyance. Anyone who knows me knows that I am certainly no stick-in-the-mud, and I'm certainly willing to forgo some amount of technical accuracy in the name of a good laugh. But for some reason, the approach taken by this site rubs me the wrong way.

I think this is a great site with a lot of potential, but it needs a bit more love and care.

17Nov/080

Proposition 8 – Flawed Arguments

There aren't any new arguments here. I just want to gather, in one place, all of the arguments in support of Prop 8 that I have an issue with.

31Dec/062

ICY MetaData (ShoutCast song titles)

I wrote a quick python script once to help me parse song metadata from ICY streams. Quite a few popular streams use this format these days, including most of the streams on ShoutCast and IceCast.

26Oct/060

Phase Cancellation

Sometimes I get excited about silly things. In this case, I experience the real-life manifestation of a mathematical concept.

10Aug/060

Dimensions and Perception

I've been doing a lot of reading about math lately — calculus, complex numbers, the discovery of the transcendental functions, and so on. I also occasionally catch a random article discussing string theory. Now, string theory I don't really understand. It discusses ideas like the possibility that our universe actually exists in many more than 3 dimension, but for some reason, the 3 that we see dominates.

Tagged as: Continue reading