with Imagination: by Dustin Diaz

./with Imagination

A JavaScript, CSS, XHTML web log focusing on usability and accessibility by Dustin Diaz

JavaScript Observer Class

Thursday, November 9th, 2006

First off, let me be the 763rd person to say that JavaScript does not have have a formal class system, however it does have the expressive nature to represent the notion of a class. That being out of the way, this entry is about representing the Observer Pattern in JavaScript; otherwise known as the publisher/subscriber model. As some already might know, it is already well demonstrated in modern event handling BOM’s such as IE’s attachEvent or W3’s addEventListener which allow you to register multiple listeners, and notify each callback by firing one event.

You might also know that some JavaScript libraries such as Dojo, YUI, and Prototype have implemented generic utilities that easily allow you to set up your publishers and allow client code to subscribe to these events….

Well, here’s mine. It’s basic and to the point, and only uses a wee bit of code.

Observer Class

function Observer() {
    this.fns = [];
}
Observer.prototype = {
    subscribe : function(fn) {
        this.fns.push(fn);
    },
    unsubscribe : function(fn) {
        this.fns = this.fns.filter(
            function(el) {
                if ( el !== fn ) {
                    return el;
                }
            }
        );
    },
    fire : function(o, thisObj) {
        var scope = thisObj || window;
        this.fns.forEach(
            function(el) {
                el.call(scope, o);
            }
        );
    }
};

Take special note that a few of the extra array methods (filter and forEach) need to be added to supplement browsers that do not support them. You could just simply grab the two from here, or just grab them all from my minified collection.

Implementation

This part is easy.

subscribing and publishing

/*
    * Publishers are in charge of "publishing" eg: Creating the Event
    * They're also in charge of "notifying" (firing the event)
*/
var o = new Observer;
o.fire('here is my data');

/*
    * Subscribers basically... "subscribe" (or listen)
    * And once they've been "notified" their callback functions are invoked
*/
var fn = function() {
    // my callback stuff
};
o.subscribe(fn);

/*
    * Don't want to subscribe anymore?
*/
o.unsubscribe(fn);

Go ahead and have a play around. See it live in action (albeit a dull and boring illustration)

16 Responses to “JavaScript Observer Class”

  1. Jaydee

    Huzzah! Great post, short and no fuzz. When’s the next YUI demo screencast coming?

  2. Bramus!

    Very interesting (and useful!)

    Thanks for posting,
    B!

  3. kentaromiura

    Why do you write
    o.subscribe(fn)

    Don’t should be something like
    fn.registerObserver(o) ?

    then you do o.fire();

    don’t should be fn.notifyObserver();

    http://en.wikipedia.org/wiki/Image:Observer-pattern-uml.jpg

    should you explaining me, please, I too done a little bit of confusion:
    http://mykenta.blogspot.com/2006/10/observer-subscriber-in-base.html

  4. Jim

    Dustin,

    I appreciate that as you wrap your mind around a concept, you share it with us. I also appreciate your slow methodical forward movement through JS and surrounding lines of thought. You take one small slice at a time, define the surrounding concepts, show us some code, explain the code, and give an example. Even if not 100% accurate 100% of the time, your willingness to share what is happening in your head is extremely helpful. I enjoy learning with you.

    Thanks Mate,
    Jim

  5. revoked

    that’s funny, I wrote an extremely similar implementation yesterday into my project and there was a bug in the .fire, so I’m just going to integrate your .fire and be on my way :) plus your solution is a bit more elegant.

  6. Dustin Diaz

    @Jaydee: Soon enough. Don’t you fret.

    @Bramus: Thanks man. Hopefully one day it will come as useful for you :)

    @Cristian: Whether it completely follows the pattern strictly is one thing. However Think of it as s set of responsibilities by each side. Publishers “publish” new Observer subjects (or objects) for all observers to see. It’s better to think of these as Events in your application that listeners can subscribe to, and that they’re attached to some other meaningful object. Let’s pretend we’re dealing with Ajax.

    funtion Ajax(url) {
        this.url = url;
        this.onComplete = new Observer;
    }

    The publisher is also responsible to notify the subscribers that their subject has gone through change (eg: that the event actually happened).

    ...
    // somewhere within the Ajax object
    this.onFoo.fire(data_back_from_the_server);
    ...

    In the meantime, subscribers are the lucky ones who also truly benefit from this style of programming. When they’re ready to make a request, they can set their callback functions into the subscription:

    // make new Ajax object
    var request = new Ajax('/my/url.php');
    // make a subscription
    request.onComplete.subscribe(
        function(data) {
            Dom.get('content').innerHTML = data;
            this.onComplete.unsubscribe(arguments.callee);
        }
    );
    // get the request
    request.get();

    @Jim: Always appreciate your feedback :) - and as a fellow YUI fan, it’s my duty to let you know that there is a much more polished version of Observer called CustomEvent which allows you to do a bit more things with data passing.

    @Revoked: Glad it came just in time :)

  7. JavaScript Observer Class « [REF]

    [...] Link [...]

  8. kentaromiura

    OK Dustin, is only because in my first implementation of this design-patterns I do
    the same thing, but after a deeper look I understand that I haven’t understand the pattern.
    In my point of view are both valid solutions.. depending on the circumstance..

    Sorry for my english, I hope you understand what I want to said.

  9. Dustin Diaz

    Christian: Ours are both respectfully different means to the same goal. Both being slight variations of the pattern. UML can tell us one thing, but alternate designs can sometimes be more elegant. Beauty is in the eye of the beholder.

  10. Nicholas C. Zakas

    I actually like the event model for the observer/subscriber pattern in JavaScript. I did something similar a while back but modeled it after events: http://www.nczonline.net/archive/2004/11/61

    I just think that implementing the strict observer/subscriber pattern as traditionally discussed is very error-prone in JavaScript. You’re assuming that the object in question has a property named onComplete (or another such name) that has a method call subscribe, so proper detection would involve looking for the object, then the observer property, then the method. On the other hand, just looking for addEventListener() requires only one step and, the part I like the most, if an event of the given name doesn’t exist, it fails quietly instead of throwing an error. :)

  11. Dustin Diaz

    @Nicholas: I suppose it’s safe to say however, considering its size, that the developer will know about what methods they’ve inherited from the Observer object. You get subscribe and unsubscribe.

    Taking perhaps the true approach to be more like the classic pattern is to extend the Function object with subscribe and unsubscribe methods. Ala:

    Function.prototype.subscribe = function(observed) {
        this.fns.push(observed);
        return this;
    };

    In this case, your Observer object becomes the “observed” and takes the role of a host. And functions can subscribe to any given host. Eg:

    var Ajax = new Observer;
    function myLogger(data) {
        console.log('data processed: '+data);
    }
    myLogger.subscribe(Ajax);
  12. Andy Kant

    RE: Cristian about the naming scheme

    The actual naming scheme of methods is up to personal preference, it doesn’t have to follow a pattern exactly. There are other names for Observer such as Publish-Subscribe that are different in name only. I personally use subscribe/unsubscribe/publish when I write observers because to me, it is easier to pick up on what the actions actually do quickly.

    On a side note, the naming scheme specified in the book Design Patterns (by Gamma/Helm/Johnson/Vlissides, a book I highly recommend) uses attach/detach/update.

  13. kentaromiura

    @Andy:
    It’s not a question of Naming scheme,
    what we were talking about is a difference in the implementation,
    in one case the Observer raise the Event, in the other
    is the Subscriber that raise the Event,
    althought we both said that are both valid paths,
    for me, and for Dustin is more natural to think that
    Observer is the one who raise the event..

  14. JavaScript Publisher

    [...] As a revisit to my previous post about making an Observer Class in JavaScript, I went ahead and built something new. You can call it “Observer Reloaded,” but I’m calling it “Publisher.” It holds a more truthful meaning to the original publish/subscribe model of the Observer Pattern. [...]

  15. Dustin Diaz

    @All: I would encourage you to also see the “Publisher” version that represents a similar idea and perhaps what Christian (kentaromiura) has been trying to explain. As I’m typing this, I can see that my trackback has already been posted in the comments directly above this one :) So Click on that.

  16. Jack Slocum

    Dustin,
    Traditionally, the Observer pattern is applied to a class which needs to expose events (rather than as the event themselves). Your Observer class would be the event, the object being observed is the “Observable” (the publisher) and the subscriber would be the “Observer” (the one who listens). So the name could possibly use a little adjustment.

    Anyway, this is minor. Great post.

Get "JavaScript Design Patterns"

"As a web developer, you'll already know that JavaScript™ is a powerful language, allowing you to add an impressive array of dynamic functionality to otherwise static web sites. But there is more power waiting to be unlocked--JavaScript is capable of full object-oriented capabilities, and by applying OOP principles, best practices, and design patterns to your code, you can make it more powerful, more efficient, and easier to work with alone or as part of a team."

Buy JS Design Patterns from Amazon.com Buy JS Design Patterns from Apress

All content copyright © 2003 - 2009 under the Creative Commons License.

Archives | Blog Search