0

I need a lazy loading variables in JavaScript. Taking inspiration from Any way to define getters for lazy variables in Javascript arrays? and from Self-references in object literal declarations I have tried this solution

var console = {
  log: function(s) {
    s = s.replace(/\\n/, '<br/>');
    document.getElementById("console").innerHTML += s + "<br/>"
  }
}

function MyClass() {
  this.LazyProperty = {
    _loaded: false,
    _autoload: function() {
      console.log("MyClassLazyProperty-1 " + JSON.stringify(this));
      if (this._loaded) {
        console.log("MyClass.LazyProperty-2 " + JSON.stringify(this));
        return this;
      } else {
        setTimeout(function(self) {
          self._loaded = true;
          self.profile = {
            displayName: "Loreto Parisi"
          };
          console.log("MyClass.LazyProperty-3 " + JSON.stringify(self));
          self._autoload();
        }, 300, this);
      }
    }
  }._autoload()
  this.User = {
    username: "loretoparisi",
    _autoload: function() {
      console.log("MyClass.User-1" + JSON.stringify(this));
      return this;
    }

  }._autoload()
}

var c = new MyClass();

console.log("c.User\n" + JSON.stringify(c.User));
console.log("c.LazyProperty\n" + JSON.stringify(c.LazyProperty));
<div id="console" />

Code Explanation Supposed that I want to populate the lazy property by result of a asynchronous lookup (like a rest request), I need to keep a status of the loading at first lookup. The _autoload function makes the async lookup and sets the response properties, so I would expect to have the object filled here:

c.LazyProperty

while the result is undefined. Why?

EDIT I have found out that something happens when calling the setTimeout, so that the reference to this is lost, so I have added a defer function that shall keep it:

_defer : function() { this._autoload(); return this },

At that point the lazy loader will work properly:

var console = {
  log: function(s) {
    s = s.replace(/\\n/, '<br/>');
    document.getElementById("console").innerHTML += s + "<br/>"
  }
}

function MyClass() {
  this.LazyProperty = {
_loaded: false,
_defer : function() { if(!this._loaded) this._autoload(); return this },
_autoload: function() {
  console.log("MyClassLazyProperty-1 " + JSON.stringify(this));
  setTimeout(function(self) {
      self._loaded = true;
      self.profile = {
        displayName: "Loreto Parisi"
      };
      console.log("MyClass.LazyProperty-3 " + JSON.stringify(self));
    }, 300, this);
}
  }. _defer()
  this.User = {
username: "loretoparisi",
_autoload: function() {
  console.log("MyClass.User-1" + JSON.stringify(this));
  return this;
}

  }._autoload()
}

var c = new MyClass();

console.log("c.User\n" + JSON.stringify(c.User));
console.log("BEFORE: c.LazyProperty\n" + JSON.stringify(c.LazyProperty));
setTimeout( function() {
   console.log("AFTER: c.LazyProperty\n" + JSON.stringify(c.LazyProperty));
},1000);
<div id="console" />

Given this solution, in the first execution I don't get why the property is undefined after it has been assigned.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
loretoparisi
  • 15,724
  • 11
  • 102
  • 146

0 Answers0