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
    Welcome to My New Office

    My first professional web development was at a small print shop where I sat in a windowless cubical all day. I suffered that boxed in environment for almost five years before I was able to find a remote job where I worked from home. The first...

  • By
    5 Ways that CSS and JavaScript Interact That You May Not Know About

    CSS and JavaScript:  the lines seemingly get blurred by each browser release.  They have always done a very different job but in the end they are both front-end technologies so they need do need to work closely.  We have our .js files and our .css, but...

Incredible Demos

  • By
    CSS Tooltips

    We all know that you can make shapes with CSS and a single HTML element, as I've covered in my CSS Triangles and CSS Circles posts.  Triangles and circles are fairly simply though, so as CSS advances, we need to stretch the boundaries...

  • By
    CSS @supports

    Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS.  What we end up doing is repeating the same properties multiple times with each browser prefix.  Yuck.  Another thing we...

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!