Lazy Object Initialization

By  on  

The Firefox DevTools underlying code, which is written with JavaScript and HTML, is a complex application. Due to the complexity and amount of work going on, the DevTools team has done everything they can to load as little as possible. Furthermore the team has a system of lazily importing and initializing objects when they're needed. I've taken a bit of time to reduce the initializer, let's take a look!

The system relies on taking advantage of Object.defineProperty's get function to initialize an object when needed:

// Lazily initializes an object's property until it's used
function lazyGet(hostObj, name, initializer) {
    let defined = false;
    Object.defineProperty(hostObj, name, {
        get: function () {
            // If not already defined, define it by executing
            // its initializer and setting it as value
            if (!defined) {
                defined = true;
                // Overrides the original property definition
                // which is the initializer
                Object.defineProperty(hostObj, name, {
                    configurable: true,
                    enumerable: true,
                    value: initializer.apply(hostObj),
                    writable: true,
                });
                return hostObj[name];
            }
        },
        configurable: true,
        enumerable: true
    });
}

With the lazyGet function, the property you want is only initialized and processing down when its getter is called:

// Don't define window.myProp until someone tries to use it
// Thus, if it's never used, it's never initialized
lazyGet(window, "myProp", () => {
    return { message: "Hello!" };
});

// window.myProp is now undefined, since it hasn't been requested yet

// Use it for something, which triggers initialization and returns its value
console.log(window.myProp.message);

// Using it again doesn't initialize again, since it was already created
console.log(window.myProp.message);

// And it can be reassigned later on:
window.myProp = null;

Mozilla's initializer is much more complex as it also acts as a loader, but you get the idea. We always think about lazy loading resources but it's also good to think about initializing properties as they may not be needed! Keep a tiny footprint if you can!

Recent Features

  • By
    5 HTML5 APIs You Didn’t Know Existed

    When you say or read "HTML5", you half expect exotic dancers and unicorns to walk into the room to the tune of "I'm Sexy and I Know It."  Can you blame us though?  We watched the fundamental APIs stagnate for so long that a basic feature...

  • By
    fetch API

    One of the worst kept secrets about AJAX on the web is that the underlying API for it, XMLHttpRequest, wasn't really made for what we've been using it for.  We've done well to create elegant APIs around XHR but we know we can do better.  Our effort to...

Incredible Demos

Discussion

  1. This is a nice idea. I think a better example to demonstrate lazy initialization might be:

      return new Date();
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!