We’ve recently added two new API’s on XPCOMUtils that make a common coding pattern simpler to do. It is quite common to have “smart getters” to store a reference to a service that you use in JavaScript. Normally, folks write code that looks something like this:
this.__defineGetter__("_ioService", function() { delete this._ioService; return this._ioService = Components.classes["@mozilla.org/network/io-service;1"]. getService(Components.interfaces.nsIIOService); });
That gets long and verbose if you have any more than a few of these getters. The new approach looks like this:
XPCOMUtils.defineLazyServiceGetter(this, "_ioService", "@mozilla.org/network/io-service;1", "nsIIOService");
The net result is a lot less boilerplate code, which, in my opinion, is a lot nicer to read. I’ve already converted the toolkit code in the Places module over, and the resulting code is much nicer.
Sometimes, however, you want to have a getter for something that is not a service. That’s where the second API comes in. You can pass in a lambda function that will be called when the value is needed for the first time. From then on, the value is cached. Some old code may look something like this:
this.__defineGetter__("_db", function() { delete this._db; return this._db = Components.classes["@mozilla.org/browser/nav-history-service;1"]. getService(Components.interfaces.nsPIPlacesDatabase). DBConnection; });
With the new API, that code turns into this:
XPCOMUtils.defineLazyGetter(this, "_db", function() { return Components.classes["@mozilla.org/browser/nav-history-service;1"]. getService(Components.interfaces.nsPIPlacesDatabase). DBConnection; });
Again, much nicer looking! If you are interested, the implementation of these methods can be found here.