The If Works This dirt was a building before

Evented programming patterns: Round-up

This post is part of a series on event-driven programming. The complete series is:

Over the last few articles, I’ve covered a few of the evented programming patterns I use most often. It’s by no means an exhaustive account but there’s plenty of mileage in these simple techniques. Applying them can lead you to highly modular, flexible and responsive software. A quick recap of what we’ve seen so far:

These cover at least 90% of my async programming habbits when writing GUIs, and Faye (a non-blocking Bayeux client/server library) uses all three patterns extensively. Which brings me to my next point: though I’ve been doing all these articles with JavaScript, the patterns are not JavaScript-specific. JavaScript is a great language for this sort of work, which is one reason Node.js is so great, but really any language with first-class functions and lexical closures should be a good tool here. For example, two of the patterns I’ve talked about exist in Ruby as Observable, Eventful and EM::Deferrable. In the Python world there’s Twisted, though I’m afraid that’s all I can tell you about it. And it should go without saying that any halfway decent Lisp should be good at this sort of thing.

If you want to get started with evented Ruby you should really take a look at EventMachine and its various contributed gems. Ruby is a more complex language than JavaScript, especially with regard to function-like objects and its scoping rules, and personally I don’t find it as nice as JavaScript for event-driven work. It’s close, just not quite as good. To make up for criticising his screencast the other day I’m going to point you to Yehuda Katz on Ruby blocks and callables – both are required reading for working with functional Ruby.

To round off the series, I’m going to cover some general concerns when working with event-driven code. These apply to all the patterns I’ve covered; I left them out of the original articles partly so as not to repeat myself and partly so as not to obscure the core ideas being presented.

First, and I can’t stress this enough: you need to be very careful about state. In JavaScript you don’t have thread safety to worry about, but the fact remains that when you bundle up a section of code as a callback function, that code could potentially run at any time in the future. If there’s high latency in your async I/O, or if an event fires when you weren’t expecting it, your callback function needs to make sure that what it’s going to do still makes sense when it eventually gets called. For example, if you’re going to update a DOM element, does that element still exist? Apply a little paranoia and you’ll be fine.

Second, and I mentioned this in a previous post: make sure that you never write two callback functions that depend on each other. Relying on execution order means you’re very tightly coupling your code to the implementation of whatever event scheduler is managing your application, be it the browser runtime, the EventMachine loop, etc. Callbacks should be independent, atomic units of code that will behave sanely no matter when they execute. Remember: async code means you have no idea when a block of code will actually run, so don’t make any silly asumptions. The example I gave before was of two callbacks for the same event, one of which sets a value that the other is expected to use:

$("ul.tabs").bind("change", function(e) {
  // Set a value
  $(this).attr("selected", e.target);
});

$("ul.tabs").bind("change", function() {
  // Use the value
  $(this).attr("selected").show();
});

If you see code like this, consider refactoring into a single cohesive callback or find another way to decouple the event handlers.

Third it’s worth mentioning error handling. When you implement a callback system, your methods are going to be calling functions from other parts of your application, or even third party code. If one of the callbacks in a list throws an exception, you don’t want that to block execution of the other callbacks or of the rest of your method. Dean Edwards wrote about this last year, though his post specifically deals with using the DOM to dispatch events since it handles errors gracefully. Exactly how you deal with errors will depend on your app: you might not want to catch them, you might want to catch and log them, you might want to do some automatic recovery, but the important thing is you need to make a decision one way or another.

In JavaScript, you have several options. If you’re client-side, you can use the DOM as described in Dean’s article, you can use try/catch or you can use setTimeout()to schedule each callback asynchronously so it won’t block the others if it fails. Here’s a couple of examples of how you’d modify your dispatch loop; listeners is an array of [callback, scope] tuples.

// Catch errors and log them with Firebug
for (var i = 0, n = listeners.length; i < n; i++) {
  try {
    listeners[i][0].call(listeners[i][1]);
  } catch (e) {
    if (window.console) console.error(e);
  }
}

// Use setTimeout for async scheduling
for (var i = 0, n = listeners.length; i < n; i++)
  (function(x) {
    setTimeout(function() {
      listeners[x][0].call(listeners[x][1]);
    }, 0);
  })(i);

The setTimeout() illustrates the point about keeping your listeners independent – if events are dispatched asynchronously you’ve got even less of a guarantee about execution order. Most event systems do execute callbacks in sequence but there’s nothing to say they couldn’t execute them out of sequence or in parallel. It also shows how in some situations you’ll need an extra closure; in this example we use a closure to fix x to the value of i for that iteration, because if we didn’t do that the asynchronously dispatched function would use the value of i from the end of the loop every time it was called. Did I mention you should be careful with state?

Finally, think carefully about which pattern makes sense for implementing a feature. For example I recently used a Deferrable when I should have just used an async method; the stored callback hung around in memory after some initial check to decide whether to run it returned false, then the callback fired much later on when I wasn’t expecting it, resulting in multiple copies of UI elements being generated. Getting it right requires a little experience to get a feel for how to structure evented code – hopefully this series has helped point you in the right direction.


3 Comments

[...] Evented programming patterns: Round-up: Всъщност това е серия от пет много добри постове. [...]

Posted by Какво ново в последната седмица на Февуари | NeXt on 28 February 2010 @ 12pm

Great set of posts!

One thing I wanted to mention was that using your recommended approach of setTimeout(func, 0); does not work properly.

The ‘i’ variable gets closured properly but in the context of setTimeout function, it is still being changed by the for loop. So essentially all the callbacks throw errors as ‘i’ is still changing and will most likely be equal to listeners.length.

We remedied this by wrapping the setTimeout function argument in its own auto invoked function as declared below.

    setTimeout(function(x){
        return(function(){
            // code here using x
        });
    }(i), 0);

Cheers,

Brent.

Posted by Brent Lintner on 3 March 2010 @ 8pm

Thanks for the correction, Brent. I’ve updated the article to reflect your suggestion. I usually use Array#forEach which stops such problems from happening, but thought I should use JavaScript common to all browsers for these examples. A good illustration of how useful closures can be!

Posted by James Coglan on 4 March 2010 @ 12am

Leave a Comment