24

I am a novice JavaScripter and have no real knowledge of what goes on inside the V8 engine.

Having said that, I am really enjoying my early forays into the node.js environment but I find that I am constantly using events.EventEmitter() as a means to emit global events so that I can structure my programs to fit a notifier-observer pattern similar to what I would write in say an Objective-C or Python program.

I find myself always doing things like this:

var events = require('events');

var eventCenter = new events.EventEmitter();

eventCenter.on('init', function() {
    var greeting = 'Hello World!';
    console.log('We're in the init function!);
    eventCenter.emit('secondFunction', greeting);
});

eventCenter.on('secondFunction', function(greeting) {
        console.log('We're in the second function!);
        console.log(greeting);
    eventCenter.emit('nextFunction');
});

eventCenter.on('nextFunction', function {
    /* do stuff */
});

eventCenter.emit('init');

So in effect I'm just structuring 'async' node.js code into code that does things in the order I expect, instead I'm kind of "coding backwards" if that makes sense. Would there be any difference in doing this in a callback-heavy manner, either performance-wise or philosophy-wise? Is it better to do the same thing using callbacks instead of events?

  • If you find your code readability suffering due to heavy use of callbacks, consider making use of a framework to wrap your use of callbacks. It takes a bit of adjustment, but promises can often untangle ugly callbacks. If you're using JQuery, you could use Deferred. One of the simplest promise frameworks is RSVP. – Brian Nov 23 '13 at 1:32
  • I'm confused, I don't see anything async in your code, just function calls written in an overcomplicated way. – svick Nov 28 '13 at 20:27
27

The nice thing about callbacks is there's no global state there, and passing parameters to them is trivial. If you have a function download(URL, callback: (FileData)->void) then you can know that's a self-contained higher-order function which essentially lets you construct a "grab this and do that" function. You can be sure your code flow is exactly as you expect, because nobody else even has a handle on that callback, and that callback doesn't know about anything but the parent function's given parameters. That makes it modular and easy to test.

If you now want to download 5 files in parallel and do different things, you need only fire five of these functions off with the appropriate callback functions. In a language with good anonymous function syntax this can be incredibly powerful.

Events, on the other hand, are more designed for notifying 1..* users of some state change. If you fire a "download complete" event at the end of download(URL), which launches processDownload() which knows where to find the data, you're tying your implementations of things to a larger amount of state. How do you parallelise downloads now? How do you handle the different downloads differently? Is download(URL, eventId) elegant? Is downloadAndDoThing(URL) elegant? Hardly.

Of course, as with all things, you are making tradeoffs. Nested callbacks can make the order of execution of code more confusing, and the lack of easy global accessability makes it a poor choice for anything where you do have a 1..* relationship between producer and consumer. You have a harder time passing data around, but if you can get away with not having additional state then that's usually a benefit anyway.

Regardless. You're coding in node.js where callbacks are idiomatic, and the language and libraries are designed around their use. Whether you see advantages in one design or another, I think it's almost always true that writing idiomatic code in any language is going to have far greater support and make your life much easier than trying to circumvent it.

2

I've never used events in NodeJS, but generally what I use clientside JS events for is signaling that something has happened, e.g. an AppointmentBookedEvent, so that different parts of an SPA view can react to that (show it in a timeline, load it in a panel, etc).
But using events to signal a method has completed can be a dangerous road to travel. You can't rely on events to arrive in the same order they were fired, so that could lead to all sorts of randomness...
There's nothing wrong with using events, but there's a certain level of granularity that you shouldn't go under; if you stick to domain-ish events, that's fine. But notifying that methods have finished is too granular.

0

Something you might explore is usage of the events outside the object which is emitting them. In your example, eventCenter appears to both emit and handle its own events. Consider how the structure of your application might change if other objects begin to handle the events.

So, eventCenter might emit "init", which other objects could then handle to do their startup code, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.