Writing Compressible JavaScript

Writing a library is a balancing act between the (sometimes competing) interests of API clarity, code clarity, performance and compressibility. In this article I'm going to detail three of the approaches we take to meet this balance and suggest them for your own usage.

1. Collecting var statements

Every time we declare variables we add 4 bytes to the compressed file size. Variables are declared sufficiently often that this can really add up, so instead of this:

var myFirstVar = 'something';
var myOtherVar = 'another thing';
var answer = 42;
var adama = true;
var myFirstVar = 'something';
var myOtherVar = 'another thing';
var answer = 42;
var adama = true;

One should use this form:

var myFirstVar = 'something',
myOtherVar = 'another thing',
answer = 42,
adama = true;
var myFirstVar = 'something',
myOtherVar = 'another thing',
answer = 42,
adama = true;

When this code is compressed, each variable name above is turned into a single-letter name, meaning that the wasted 4 bytes per useless additional 'var ' in the first example would have contributed significantly to code size with no benefit.

2. Local variable pointers to object properties

The following code (pruned from a previous version of Ext JS) is not as compressible as it could be:

var cs = {};
for (var n in this.modified) {
if (this.modified.hasOwnProperty(n)) {
cs[n] = this.data[n];
}
}
return cs;
var cs = {};
for (var n in this.modified) {
if (this.modified.hasOwnProperty(n)) {
cs[n] = this.data[n];
}
}
return cs;

We're better off aliasing 'this.modified' to a local variable first. Aside from the performance benefits some JS engines derive from not having to perform object property lookups over and over again, we save precious bytes this way too:

var modified = this.modified,
changes = {},
field;

for (field in modified) {
if (modified.hasOwnProperty(field)) {
changes[field] = this.data[field];
}
}

return changes;
var modified = this.modified,
changes = {},
field;

for (field in modified) {
if (modified.hasOwnProperty(field)) {
changes[field] = this.data[field];
}
}

return changes;

Again, the minifier will compress those variable names down to a single character each, so for our 'this.modified' example we're going to use 15 bytes to define the variable plus 1 byte each time we use it (totalling 15), vs the 26 bytes for that code previously. This approach scales especially well - were we to refer to this.modified a third time in the function, as our code will now minify to 16 bytes, vs 39 without the variable declaration.

Side note: in the first example here the variable 'n' was being used in the for...in loop. We can always safely exchange that for a meaningful variable name (in this case 'field') and leave the rest to the minifier.

3. Aliasing 'this' to 'me'

In Ext.data.Record's markDirty method we have the following code:

this.dirty = true;
if(!this.modified){
this.modified = {};
}
this.fields.each(function(f) {
this.modified[f.name] = this.data[f.name];
},this);
this.dirty = true;
if(!this.modified){
this.modified = {};
}
this.fields.each(function(f) {
this.modified[f.name] = this.data[f.name];
},this);

There are 7 references to 'this' in that method, taking 28 bytes and completely incompressible. We could rewrite it like this (note that the final 'this' can be removed in this format):

var me = this;

me.dirty = true;
if (!me.modified) {
me.modified = {};
}
me.fields.each(function(f) {
me.modified[f.name] = me.data[f.name];
});
var me = this;

me.dirty = true;
if (!me.modified) {
me.modified = {};
}
me.fields.each(function(f) {
me.modified[f.name] = me.data[f.name];
});

Again, our minifier will change the 'me' var to a single character, saving us 8 bytes in this instance. That might not sound like a lot but after minification it equates to a 7% reduction in code size for this function.

In each of the cases above we're generally talking about single-digit percentage savings after minification. There is value in that small slice though, especially as more and more applications shift onto bandwidth-constrained mobile platforms.

The first two approaches are no-brainers and must always be done but the third is slightly more controversial. Personally I find it makes the code a little harder to read, largely because my syntax highlighter doesn't recognise that 'me' is now the same as 'this'. Its value also varies significantly by function - some functions can contain over a dozen references to 'this', in which case this approach makes a big difference.

Share Post:

What to Read Next

On Leaving Sencha

As some of you may know, I left Sencha last week to move to another startup just up the road in San