Binding (and unbinding) JQuery Event Handlers in a Complex Web App

I’m commonly placed in a tough situation. Here I am, working on a web related project and I would like to implement a lot of complex features via javascript. JQuery is the first library I’ve used and it has allowed me to at least dream of a functional, yet complex, web application. Typically, the first 25% of the javascript related work is a total breeze, thanks to jquery. The next 30-50% of the work becomes totally convulated, thanks to jquery being my crutch, and never diving in and bothering to understand javascript all these years. The final percent is ussually left on a wish-list of too-buggy-to-deploy and wouldn’t-it-be-nice.

Here I am again, endeavoring to build a complex and functional web application and this time I really want to get it right, and low and behold, I’m beginning to run into one of those typical problems.

Binding Events with JQuery

JQuery really makes this easy. I love it. I remember first starting off and writing a little bit of code like this:

$('.button').click(function() {
  $.get('/some/stuff', function() {
    $('.somestuff').append(....);
  });
});

and what not. Then I discovered that beloved .load() function. Really cut down on a lot of legwork I was doing. But there was always a slight problem. I always ended up with conflicting binds. There were various ways I worked around this, among other problems before .live() was around, but it was always a bit of a conundrum. I think this mostly deals with the approach JQuery takes towards usability. The focus is quickly accessing an object and binding the specified event, nothing more. It makes no effort to force any sort of design paradigm, which leads me to wonder, how should I handle this? I figure the first place to look for inspiration are in libraries I already currently use that solve this sort of design pattern.

Pyglet Event Handling for OpenGL/Python

I’ve used pyglet for a while now. It has a few design patterns for handling events that go something like this:

# first, it allows for decorators over a method
@windows.event
def mouse_press(...):
    pass # and do stuff

# and also a window method to push handlers of class instances
class SomeStuff(object):
    def mouse_press(...):
        pass # and go

some_stuff = SomeStuff()
window.push_handlers(some_stuff)

# and likewise, you can pop those handlers
window.pop_handlers(some_stuff)

The first design pattern doesn’t really solve any particular problem of mine and is pretty much already what is going on using jquery events. But the second pattern is something I would have considered impossible for me to accomplish in javascript, I’ve just never understood the language enough to consider it doable. But recently, I’ve been coming to understand the language a lot more and wrote a small utility for making better use of prototypal inheritance in javascript, js.js, and it struck me that this would be pretty easy to implement.

A Design Paradigm for JQuery Event Handling

First, its important to understand a small bit about the js.js utility. It’s somewhat based off of Crockford’s function that prototyped an empty constructor with a passed in object. The difference here is that js.js calls magic methods (instead of being an empty constructor) and allows one to pass in multiple objects and functions to be prototyped.

The design consists of two parts. A jquery plugin in the form of $.events.push() and $.events.pop() and a prototype inheritance pattern, optionally using the js.js function.

This is the plugin code:

$.extend({
    events: {
        recurse: function(args, action) {
            for (var x in args) {
                var obj = args[x];
                for (var k in obj) {
                    if (typeof obj[k].bind != "undefined") {
                        if (action == "push") {
                            $(obj[k].bind).bind(k, obj[k], obj);
                        } else {
                            $(obj[k].bind).unbind(k, obj[k]);
                        }
                    } else if (typeof obj[k].live != "undefined") {
                        if (action == "push") {
                            $(obj[k].live).live(k, obj[k], obj);
                        } else {
                            $(obj[k].live).die(k, obj[k]);
                        }
                    }
                }
            }
        },
        push: function() {
            this.recurse(arguments, "push");
        },
        pop: function(obj) {
            this.recurse(arguments, "pop");
        }
    }
});

The scenario is this. A lot of ajax events are very similar and would work across different loaded pages/forms. Where necessary, one could override an event to add extra functionality:

controls = {
  index: function(params) { $(...).load(...); },
  form: function(params) { $(...).load(...); },
  save: function(data) { $.post(..., this.index); }
}

events = {
  keyup: function() { ... },
  submit: function() { ...; this.save(data); return false; }
}
events.keyup.live = '.main .filter'; // just demonstrating access to live and bind
events.submit.bind = '.main .form';

user = function() {
  this.init = function() {
    $('a[href=#user]').bind('click', this.click, this);
  }
  this.click = function() {
    highlight(...);
    // do some more stuff;
    this.index();
    this.form();
    
    $.events.pop(one, two, three);
    $.events.push(this);
  }
}

var User = prototype(user, events, controls, object);

$(function() {
  var u = new User({url: '/db/User'});
});

This allows for common parts to be factored out when shared by many different objects. Picture five other objects alongside User. Some might override events and call the original, for example, events.submit.call(this, …).

This is a little rudimentary to start, but its a start none-the-less.

Advertisements

A Javascript Class with magic methods

Hey, ok so this is what i have so far, totally preliminary

function class() {
    var that = function() {
        this.__init__(arguments[0]);
    };
    that.prototype = new object;

    for (var x=arguments.length-1; x>=0; --x) {
        var m = new arguments[x];
        for (var i in m) { that.prototype[i] = m[i]; }
    }
    this[arguments[0].name] = that;
}

function object() {
    this.__init__ = function(kwargs) {
        for (var k in kwargs) {
            this[k] = kwargs[k];
        }
    }
}

Short, right?

Then I can write something like this,

class(A, object)
function A() {
    this.get_name = function() {
        return this.name;
    }
}

class(B, A)
function B() {
    this.get_age = function() {
        return this.age;
    }
}

class(C, object)
function C() {
    this.__init__ = function() {
        this.name = "OVERRIDE";
    }
}


var a = new A({name: "Daniel", age: "24"});
var b = new B({name: "David", age: "25"});
var c = new C({name: "John", age: "26"});

effectively just sticking a little header over normal javascript functions, and everything works as one would expect.

a.name // returns Daniel
a.age // returns 24
b.get_age() // returns 25
b.get_name() // returns David
c.name // returns OVERRIDE

And to boot, it executes at the same speed as writing it the “native” way. Here’s what i have for “native” (im a noob so correct any errors)

function object() {}
object.prototype.init = function(kwargs) {
    for (var k in kwargs) {
        this[k] = kwargs[k];
    }
}

function A(kwargs) {
    this.init(kwargs);
}
A.prototype = new object;
A.prototype.get_name = function() {
    return this.name;
}

function B(kwargs) {
    this.init(kwargs);
}
B.prototype = new A;
B.prototype.get_age = function() {
    return this.age;
}

function C() {
    this.name = "OVERRIDE";
}

I ran a test importing each implementation, respectively, and got similar results in execution speed and memory size. I created 100,000 thousand objects of each A, B, C and each method occupied 78mb according to top, and each method consistently ran between 2100-2300 ms with variance that occasionally hit 3000 ms. Ultimately its not surprising as all the class function i wrote does is auto write how you would do it natively. What Im surprised about is theres no extra cruft when the javascript runtime compiler handles it. I never intended this to be useful, it was all part of an experiment delving into javascript scope and messing with constructors so i could evaluate the use of a library like prototype.js or mootools.

But hell, so far this little bit of code is turning out to be fairly useful. I imagine if i write more magic methods, the memory size will increase by a small amount. I half expected to see a difference in memory since the C is much more stripped down in “native” version vs the version with __init__ cruft from object function.

This has all been using spidermonkey-bin (smjs) so now im curious to see how other javascript implementations handle the details, as from the get-go i expected a huge increase in memory (not that I know anything about anything) from functions existing in the constructor and then being linked to a prototype, and all those “new” instances called in class. But it all seems negligible, in spidermonkey anyway. This could be a totally different story in IE, lol

for reference, heres my lame-o profile code (i know, i know, but it was enough to find all sorts of issues when exploring javascript scope and constructors)

var date1 = new Date(); 
var milliseconds1 = date1.getTime(); 

load('custom.js'); // point this to which script to test
var l = [];
for (var j = 0; j < 100000; ++j) {
    l.push(new A({name: "Daniel", age: "24"}));
    l.push(new B({name: "David", age: "25"}));
    l.push(new C({name: "John", age: "26"}));
}

var date2 = new Date(); 
var milliseconds2 = date2.getTime(); 

var difference = milliseconds2 - milliseconds1;
print(l.length)
print(difference)

*** EDIT *** Also, function object needs a class(object) so you can call its magic methods, so in C this.__init__ = function(kwargs) { object.prototype.__init__.call(this, kwargs) }
Of which, im a little confused, b/c I originally expected to not work. Anytime a Class(X) is called, its constructor gets replaced, so another Class(X) later on will be referring to that replaced class which i thought would cause some kind of error, or so i would think. So deep inheritance might cause some bad mojo with the amount of memory or hell if i know. I haven’t looked into that yet
*** EDIT 2 *** Also, im not sure how much of a “class” this is really, if it turns out useful i may find a different name, maybe just call it “prototype” so like
prototype(A, object)
function A() {};
var a = new A({name: “daniel”});

Baffling Results from my Javascript Class(-ishness)

** Edit, regarding the following, I suddenly realized what the problem was, .call is slow and was used in the “native” approach. Nevertheless Ive had positive result following through on multiple inheritence and magic methods. refer here, http://wp.me/piHZk-14 **

Ok, So recently I’ve taken an interest in javascript. By interest I mean taking it more seriously as a language. One of the first things I wanted to do was to see if I should adopt a framework like mootools to allow for classical inheritance type of stuff or if I should develop using the prototypal javascript inheritance. This lead me to really dig in deep to javascript scope and all of its nuances, especially considering prototype.

Along the way, pecking away at my smjs console (aptitude install spidermonkey-bin), I eventually wrote this function class() {} as I was trying to see what I could get away with in poking at the scope of functions and their prototypes. I was particularly annoyed with a seperation between the constructor and that which was prototyped and the foresight required, which Im going to lack since Im new to the game. Anyway, heres the function,

function class() {
    var that = arguments[0];
    for (var x=arguments.length-1; x>=0; --x) {
        m = new arguments[x];
        for (var i in m) { that.prototype[i] = m[i]; }
    }
}

effectively, this allowed me to write my prototypes in the constructor as well as extend functions. It was all in the name of learning and I wasn’t considering it practical. So basically I wrote stuff like

function object() {
    this.init = function(kwargs) {
        for (var k in kwargs) {
            this[k] = kwargs[k];
        }
    }
}

class(A, object)
function A(kwargs) {
    this.init(kwargs);
}

var a = new A({name: "Daniel", age: "24"});

I was also playing around with object constructors (unsuccessfully) curious as to if i could implement magic methods that could be inherited and run automatically, but yeah, that went no where so i was all but about to abandon this whole excursion when I decided, before I do, I wonder how much more memory my function class() {} uses and how much slower it is from doing it the standard way. By standard, I mean what I basically learned from perusing the net and from MDC javascript 1.5 Engineering Model Example. Heres what I have for the “standard” way

function object() {}
object.prototype.init = function(kwargs) {
    for (var k in kwargs) {
        this[k] = kwargs[k];
    }
}

function A(kwargs) {
    object.prototype.init.call(this, kwargs);
}

var a = new A({name: "Daniel", age: "24"});

Now my profiling isn’t very scientific I suppose, I used top and timed the execution from within javascript, but the results are consistent. What I basically did was this

var date1 = new Date(); 
var milliseconds1 = date1.getTime(); 

load('test2.js');
var l = [];
for (var j = 0; j < 5000; ++j) {
    l.push(new A({name: "Daniel", age: "24"}));
}

var date2 = new Date(); 
var milliseconds2 = date2.getTime(); 

var difference = milliseconds2 - milliseconds1;
print(l.length)
print(difference)

where load(‘test2.js’) was the “standard” way and load(‘test4.js’) in a seperate file was my way. The first thing that caught me off guard was that memory consumption was the exact same. I was half expecting my method to take more memory b/c the function definations existed in two places, but I guess the javascript runtime compiler doesn’t cause this to happen, so yippie freaggin do da. Now what left me baffled was that my way was consistently faster then the standard way. Here are the time results, running 10 in a row

* all times are in milliseconds
=== Standard ===
54
58
49
55
55
53
53
49
53
52

=== My Way ===
42
41
42
45
45
42
42
48
48
48

The numbers were close, so then i decided to increase the number of objects created to perhaps provide a more significant and visible difference. So I increased the number of objects from 5,000 to 500,000.

=== My Way ===
5716
4257
4229
4331

=== Standard Way ===
7601
4866
4913
5564

Its as if the javascript compiler runs faster instantiating an object property and linking it to a prototype then it does when just instantiating a prototype property. And it doesn’t require any extra headway in memory to do it.

If theres any javascript ninja’s that can explain whats going on, thatd be simply awesome. Speaking of which, im gonna go find mailing list now…