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.

4
  • ETLDR - please shorten your question! Commented May 12, 2016 at 13:36
  • @Alnitak done, I have removed the explanation in favor of shortness. Commented May 12, 2016 at 13:42
  • IMHO it's still about 300% too long Commented May 12, 2016 at 14:02
  • @Alnitak I have shorted again, now just few comments and two (different) code snippet, I think it is ok, don't you? Commented May 12, 2016 at 14:13

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.