The Static Module Instance wRapper Factory (SMIRF) pattern

Earlier in the year, I wrote about memory waste issues in Caveats of the JS Module Pattern. I’d like to offer a new pattern as a solution to those issues.

First, a reminder of why we like the module pattern: it provides an elegant way to have private methods and variables. For most singleton objects, there is no better option. I’ll use Christian Heilmann’s Revealing Module pattern for my examples:

var currencyExchange = function(){
  var currencies = {
    usd: 1,//always 1, base currency
    gbp: 0.631552356,
    aud: 0.99980004,
    cad: 1.0072999
  };
  var convert = function(fromCurrency, toCurrency, amount){
    var amountInUsd = (fromCurrency === 'usd') ?
      amount : amount / currencies[fromCurrency];
    return (toCurrency === 'usd') ?
      amountInUsd : amountInUsd * currencies[toCurrency];
  };
  var changeRate = function(currency, rate){
    currencies[currency] = rate;
  };
  return {
    convert: convert,
    changeRate: changeRate
  };
}();

The memory waste problem occurs when you use this pattern to create object instances:

var employeeFactory = function(name, salary){
  var giveRaise = function(percent){
    salary = salary * (1 + (percent/100));
    return salary;
  };
  var fire = function(){
    //long, drawn out legal process that takes 5000 lines
  };
  return {
    giveRaise: giveRaise,
    fire: fire
  };
};
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);

We now have created two identical but separate versions of the giveRaise and fire functions, wasting CPU in generating the duplicates, and memory in storing them.


SMIRF it down to size

Looking at the singleton example, the elegance of it is that the functions are created once as the script is first run. The reason we can’t easily do that with instantiation is that the functions need to be declared in the scope of the state variables (name and salary) that they’re operating on.

The SMIRF pattern provides a way to have the outer, static module which provides methods shared across all instance objects, avoiding most of the CPU and memory waste.

We still need to create tiny, one line “wrapper” methods for each method on an instance, but the footprint of these is minimal in comparison to that of reproducing large methods for each instance.

var employeeFactory = function(){
  /* These are STATIC functions to hold the majority of code.
   * They should be run in the context of the instance via "call",
   * and the first arg should always be iVars.
   * The "this" keyword and iVars are the only ties these methods
   * have to the object!
   */
  var giveRaise = function(iVars, percent){
    iVars.salary = iVars.salary * (1 + (percent/100));
    return iVars.salary;
  };
  var fire = function(iVars){
    //long, drawn out legal process that takes 5000 lines
  };
  return function(name, salary){
    //This is essentially a constructor function
    var iVars = {
      //Instance variables. All state info should be stored here
      name: name,
      salary: salary
    };
    var instance = {
      //This will be our actual instance object.
      //Fns here are thin wrappers for memory efficiency
      giveRaise: function(percent){
        return giveRaise.call(instance, iVars, percent);
      },
      fire: function(){
        return fire.call(instance, iVars);
      }
    };
    return instance;
  };
}();
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);

Note that the methods on the instance object will never vary much from what you see above. They simply run the static methods in the context of the instance, passing the instance variables, and pass back the returned value.

All private variables should be stored in iVars, so that the static method signature is always the same. Publicly accessible variables, of course, would simply be on the instance object itself, accessible via the “this” keyword in the shared static methods.

Caveats of the JS Module Pattern

Javascript modules are a nifty construct which I was lucky enough to learn firsthand from Douglas Crockford in his (then) small classes at Yahoo c2005. He didn’t use the term “module pattern” then — I expect he hadn’t thought of the phrase yet. It was just a way to have private variables and methods.

I still love them, but I have some caveats with regards to using them for non-singleton objects.

First, what is a module?

var counter = function(){
    var my = {
        count: 0,
        max: 5,
        isPastMax: function(){
            return this.count > this.max;
        }
    };
    //This is what gets assigned to the variable "counter"
    return {
        getCount: function(){
            return my.count;
        },
        reset: function(){
            my.count = 0;
        },
        increment: function(){
            my.count++;
            if (my.isPastMax()) {
                this.reset();
            }
        }
    };
}(); //NOTE the (). That makes the outer function run and return immediately

A module is nothing more than a function which returns a public API object which, through the magic of closure, has access to truly private methods and variables. Here I’ve put them all as properties of private variable my.

counter is now a singleton object that maintains a counter state privately. No more methods can be added to it which reach anything in my that we haven’t explicitly allowed.

This is all well and good. But what if we want more than one counter? Let’s take off the trailing () so that we have a factory that produces counters:

var Counter = function(){
   //just as above
}; //NOTE the absence of ()!
var instances = [];
for (var i=0; i<100; i++) {
    instances.push(Counter());
}

Now we have 100 instances of the Counter module!

Unfortunately, the encapsulation has come with a price in this case. Every function we defined within Counter has to be created again and occupy more memory!

Sometimes this is acceptable, if the number to be created is low and the module is small. If you’ve got a module that goes on for a few pages and you intend to make a few dozen instances, expect to be eating up substantially more memory than a similar feature using a non-encapsulated object, like so:

var Counter = {
    _count: 0,
    _max: 5,
    _isPastMax: function(){
        return this._count > this._max;
    },
    reset: function(){
        this._count = 0;
    },
    increment: function(){
        this._count++;
    },
    getCount: function(){
        return this._count;
    }
};
Object.extend = Object.extend || function(a, b){
    for (var k in b) {
        if (b.hasOwnProperty(k)) { a[k] = b[k]; }
    }
    return a;
};
var instances = [];
for (var i=0; i<100; i++) {
    instances.push(
        Object.extend({}, Counter)
    );
}

All of the functions exist only once in memory, referenced by the individual instance objects.

Make no doubt: the module pattern is a tool that every good Javascript developer should understand. It provides excellent encapsulation that can’t be externally broken. It’s not without its drawbacks, however.

Resize-to-window web apps

One of the things Flash designers have had which web developers have not is the ability to retarget an application to any viewport size desired. I’ve been saddled with implementing a by such a Flash designer for deployment in HTML/CSS/JS on QTwebkit.

What’s amazing is that I’ve had some degree of success with it. I can’t show a demo yet, but imagine that a fully animated, complicated application smoothly scales, centres, and otherwise behaves more or less like you’d expect Flash to.

To be sure, there are some sketchy areas. Webkit’s positioning math can be very sloppy if you need precision (my design does). Any container that’s affected by font size is going to change a little (not always bad).

Watch here for a demonstration of this soon, along with a bit of how-to.

Improved jquery ajax error reporting

jQuery is a great library, and I highly recommend it after 6 months of use. One of the problems I’ve had with it, however, is its poor error reporting on ajax requests. While you can subscribe to the global event ajaxError, there’s nothing to tell you what went wrong. Specifically, I’ve wanted a way to report when the json parse fails.

Looking through the jQuery core, I found that the problem is that “status” field isn’t sent to the handler. A simple intervention on jQuery.handleError will close the gap:

jQuery.handleErrorOriginal = $.handleError;
jQuery.handleError = function( s, xhr, status, e ){
  if (s.global) {
    xhr.error_status = status;
  }
  jQuery.handleErrorOriginal.apply(this, arguments);
};

The “e” object is the original ajax configuration object. Since it reaches the global ajaxError listener, we can pull the status out of that.

Notice that I don’t replace the original functionality, I just do something before calling it with the same scope and arguments. The reason here is forwards-compatibility. Assuming that the name and api of jQuery.handleError doesn’t change, any changes to its internal functionality in future updates will likely be preserved without refactoring effort on your part.

To catch the errors:

$("html").ajaxError(function(xhr, s, e){
    var msg;
    switch (s.error_status) {
      case "parsererror":
        msg = "A JSON parsing error occurred.";
        break;
      case "timeout":
        msg = "An ajax request timed out.";
        break;
      default:
        msg = "An ajax error occurred.";
        break;
    }
    alert(msg + "\n\n" + e.url);
});

Why do I set xhr.error_status and then read s.error_status? Because, somewhere in the jumble of handleError and trigger, xhr becomes s. I love jQuery, but some of its core code can be quite difficult to read through.

jQuery(document).ready() bug with Google Chrome 4.0 beta

I came across a major issue with jQuery (1.3.2) and Google Chrome 4.0 beta today. I’d been testing my company’s web application (for which I’m the primary frontend developer) with Chrome 3.0x, and it was working fine. After a sudden influx of chrome bug reports from someone using 4, I updated to that. And suddenly, nearly nothing worked.

After a fair bit of futzing around in my code and the jQuery core library, I discovered that in chrome 4 in certain cases (probably in large apps), the DOMContentLoaded event was never sent to the core jQuery library. To test this, I inserted a couple of lines into the file you saw above:

3052  if ( document.addEventListener ) {
3053      // Use the handy event callback
[ins]     alert("jQ adding listener for DOMContentLoaded");
3054      document.addEventListener( "DOMContentLoaded", function(){
[ins]         alert("jQ received DOMContentLoaded event");
3055          document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
3056          jQuery.ready();
3057      }, false );

Both alerts show in FF, but only the first does in chrome. However, I found I could add my own and have them called.

Now, since the chances are you’re on this page because you googled for a workaround, here it is:

Google Chrome 4 beta jQuery document ready fix plugin

What this plugin does is first test to see if the browser is chrome 4, and if it is, then it adds another event listener for DOMContentLoaded, which will run even though the main jQuery one mysteriously does not. This calls jQuery.ready function (which is what is used to run through jQuery.readyList, the queued functions array).

We now have two chances for jQuery.ready to be called, therefore a potential race condition. To avoid this, I rewrote jQuery.ready() to null out  jQuery.readyList before cycling through the queued functions.

I still have no idea what’s causing Chrome 4 to fail on this. A test of document.readyState right after I added $(document).ready() shows that it is “loading”, so the problem isn’t that it finishes before adding the event handler or enqueueing the function.

IE and newlines from innerHTML

I ran into a problem today that I’m surprised I haven’t run into before. Internet Explorer loses newlines when pulling text from an HTML element.

In short, if you use innerHTML, innerText or outerHTML on most elements, IE will convert newlines to spaces. Checking the charCodes of newlines (whether unix or ascii) shows them as 32s.

On the other hand, if I output (in a template) the text inside a PRE element, IE will keep the newlines. An element styled with white-space:pre won’t do the trick.

In my case, I have a TD and inner DIV which contain a text string. I need to show the full text string, with line breaks, in a popup dialog. (The CSS property white-space:pre isn’t useful, since long lines can’t wrap at all.) My two realistic options are to copy the data into a JS variable or put the text initially inside a PRE element.

Got to love Microsoft. They keep us webdevs in a job.