Lazy Attributes in JavaScript

June 2, 2012

A while back, I released a tiny library called laze for making the use of lazy attributes easy in JavaScript.

I thought I’d do a post to provide some more context of how laze fits into my workflow in a node.js project.  There are definitely some terrible things you can do with this library, but hopefully this post will outline the intended use and convince you to try it out.

Imagine I want to create a new server, and then start listening on a given port.  I start out with some really tightly coupled code:

Server.prototype = {
  start: function () {
    var host = this.config.host || '127.0.0.1';
    var port = this.config.port || 8080;
    var server = http.createServer();
    server.on('request', this.handleRequest.bind(this));
    server.listen(port, host);
  }
};

This code works well, but in my opinion it just does way too much.  In here, we have logic for:

  1. Handling how to pull the host and port out of our config – and what to do if they’re not set
  2. Creating a new server
  3. Binding our server to another function for requests
  4. Starting the server listening on the given host and port

Imagine we want to start splitting this function up a bit.  We’ll start with pulling the host/port configuration out.

Server.prototype = {
  getHost: function () {
    return this.config.host || '127.0.0.1';
  },
  getPort: function () {
    return this.config.port || 8080;
  },
  start: function () {
    var server = http.createServer();
    server.on('request', this.handleRequest.bind(this));
    server.listen(this.getPort(), this.getHost());
  }
};

So this works pretty well actually – but if somewhere else in this object we’d like to have access to the host and port, we’re re-running the logic inside of `getHost` and `getPort`.  Not a big deal for these quick functions, but something that did a bit more would make that approach just wasteful.

So we could proceed in one of two ways:

Call getHost and getPort from the constructor

var Server = function () {
  this.host = this.getHost();
  this.port = this.getPort();
};

If we call the two methods from the constructor, we can have properties set that contain the proper host and port.  This is nice – but crowding our constructor with calls to methods that aren’t needed *unless* start gets called.  You can see that if these were time-intensive tasks – we’d end up wasting time for methods that may not be called at all.

Call getHost and getPort from `start`

Server.prototype.start = function () {
  this.host = this.getHost();
  this.port = this.getPort();
  var server = http.createServer();
  server.on('request', this.handleRequest.bind(this));
  server.listen(this.port, this.host);
};

This approach is good – its made our start function a bit more complicated but the separation is correct.  The one remaining problem with this approach is that if another method wants to access `host` or `port` before `start` has been called – they’ll both be undefined.

Another Option: Lazy Attributes

Laze uses `defineProperty` to give us another option.  We can define properties that won’t be set until they are used.  Then we get the best of all worlds.  The host or port can be called at any time and have the proper values.  And – once they’re called one time, they’ll hold onto their value for the next time without recomputing it.  Let’s take a look at the code:

Server.prototype = {
  start: function () {
    var server = http.createServer();
    server.on('request', this.handleRequest.bind(this));
    server.listen(this.port, this.host);
  }
};

laze.defineAll(Server.prototype, {
  port: function () {
    return this.config.port || 8080;
  },
  host: function () {
    return this.config.host || '127.0.0.1';
  }
});

If you want to – you could take this whole thing another step, and make the creation of the server lazy too.

Server.prototype = {
  this.server.listen(this.port, this.host);
};

laze.defineAll(Server.prototype, {
  port: function () {
    return this.config.port || 8080;
  },
  host: function () {
    return this.config.host || '127.0.0.1';
  },
  server: function () {
    var server = http.createServer();
    server.on('request', this.handleRequest.bind(this));
    return server;
  }
});

I hope this post gave a good overview of using lazy attributes in JavaScript with laze – if you’re interested in reading how it works check out the code (which is pretty simple), or go straight to the github page.

You can also install laze via npm:

npm install laze

Tags

Async.js is Boss

April 25, 2012

A JavaScript library I really like is async by caolan.  It makes common tasks for multiple async operations really natural, which is especially useful for Node programming.

Check it out!

Tags

Writing Node.js in CoffeeScript

April 16, 2012

Now I know I’ve spoken slightly poorly of CoffeeScript in the past, but I’ve been getting into it a bit more recently on some small libraries I’ve been writing for Node.  Turns out, it’s really easy to write parts of your Node applications in CoffeeScript and have them automatically compiled for you.

First, add “coffee-script” to your dependencies in package.json (definitely specify a real version instead of using *):

{
  ...
  "dependencies": {
    "coffee-script": "*"
  }
  ... 
}

And then, any time you need a file that’s written in CoffeeScript, just make sure you have require “coffee-script” before requiring it:

require("coffee-script");
require("./something_in_coffeescript"); // something_in_coffeescript.coffee
...

And off you go!

laze: Lazy Properties in JavaScript

March 31, 2012

Yesterday I released a small JavaScript module called laze for defining lazy properties in JavaScript.  With laze, you can have properties of an object not be created until they are accessed.

var Thing = function () { };

Thing.prototype = {
  prop: function () {
    // some expensive operation
  }
};
laze.make(Thing.prototype, 'prop');

Once you have it set up, you can access “prop” as a property instead of as a function:

var thing = new Thing();
thing.prop; // function is run now
thing.prop; // and cached forever

Tags

Trimming Strings in JavaScript

March 29, 2012

ECMAScript 5 has support for String#trim, so next time you’re trimming a String in Node (or in a web browser if you don’t care about IE 8), you can trim it like:

' hello '.trim(); // "hello"

instead of the dated regular expression approach:

return this.replace(/^\s+|\s+$/g, "");

Please (please!) use these when you can.  I’ve got a really fun post coming up on ECMAScript 5 in more detail.  Stay tuned!

Tags