0

I'm having an issue accessing a variable that is written in a JavaScript promise in the constructor of a class file. I have only used promises once, and despite doing some additional reading on them, it's still a little confusing to me, so I assume this is where I'm going wrong.

Below is the code in question:

Guild.js - This is the class with a variable set through a promise

class Guild extends MapObject {
  constructor(x, y, floor, type, name) {
    super(x, y, floor);
    this.levels = [];
    this.type = type;
    this.name = name;
    this.id = this.type + this.position.x + this.position.y;
    this.guildSelector().then((gData) => {
      this.guildData = gData;
      this.addLevels(this.name);
      this.setTip();
    });
  }

  setTip() {
    this.tip = this.name;
  }

  guildSelector() {
    return new Promise((resolve, reject) => {
      var oReq = new XMLHttpRequest();
      this.guildData = null;

      oReq.onload = reqListener;
      oReq.open("get", "/json/guilds.json", true);
      oReq.send();

      function reqListener() {
        this.guildData = JSON.parse(this.responseText);
        resolve(this.guildData);
      }
    })
  }
}

map-maker.js - Main class utilising instances of Guild.js

function createGuildObject(x, y, floor, type, name) {
  return new Promise((resolve, reject) => {
    console.log("createGuildObj");
    currentMap.objects.push(new Guild(x, y, floor, type, name));
    var currentGuild = currentMap.objects[currentMap.objects.length - 1];
    console.log(currentGuild.guildData);
    resolve(currentGuild);
  });
}

So the problem I have is when I push a new instance of guild.js to my map class (essentially a container of objects) I can access every variable of the guild except the one set during the promise (this.guildData).

Where I'm really confused is if I type:

console.log(currentGuild.guildData); directly after initialising the guild instance I see null.

But if I type:

console.log(currentGuild); I see the guildData variable with all of its content:

console.log(currentGuild)

Any suggestions?

Knut Holm
  • 3,988
  • 4
  • 32
  • 54
Farrell Coleman
  • 79
  • 3
  • 15
  • Can you create a Fiddle? – Knut Holm Aug 14 '17 at 08:46
  • Even though `createGuildObject` returns a Promise, this Promise gets executed synchronously and do `then` before `guildSelector` thened. One way would be to store guildSelector's Promise as a property of the `Guild` instance, and return this Promise in `createGuildObject` instead of the useless one you currently return. – Kaiido Aug 14 '17 at 08:47
  • 1
    [Don't create promises in constructors](https://stackoverflow.com/a/24686979/1048572). – Bergi Aug 14 '17 at 08:51
  • Hi @akarienta, I can make a Fiddle tonight, probably shouldn't do it at work :p – Farrell Coleman Aug 14 '17 at 08:52
  • 1
    seems like it's a case of knowing how to use asynchronous code – Jaromanda X Aug 14 '17 at 08:52
  • @Bergi arguably he doesn't return anything from this constructor. `guildSelector` is an orphan Promise – Kaiido Aug 14 '17 at 08:52
  • 1
    @Kaiido Which is even worse :-) Yes, while the linked question asks about returning promises from constructors, I said "creates", and the problem and solution are the same. – Bergi Aug 14 '17 at 08:54
  • @kaiddo, I'm not sure I understand, my current return for createGuildObject is the 'this.guildData' which is required for this.addLevels(), so I do need that, sorry if I'm being dense, this is all a big learning curve for me. Very dumb question, but what do you mean by resolve the promise as a property of the Guild instance? – Farrell Coleman Aug 14 '17 at 08:54
  • @Jaramonda X, this is most certainly the case. This is just a project i'm making for fun as a way to learn, but yes. My exposure to promises and classes in Javascript is next to none. – Farrell Coleman Aug 14 '17 at 08:56
  • 2
    see if [this fiddle](https://jsfiddle.net/4zagvyah/) helps (I have this urge to yell "unacceptable" :) ) – Jaromanda X Aug 14 '17 at 08:58
  • @Jaromanda X The fiddle didn't help much unfortunately, I guess a larger rewrite is in order. From the comments and links above its obvious I'm just getting things confused and not doing stuff correctly. Back to the drawing board! – Farrell Coleman Aug 14 '17 at 09:20
  • 1
    @Bergi, just wanted to say thank you for the link about not creating promises in constructors. I moved my promise and the XMLHttpRequest out of the constructor and the class all together and instead now load the data in a promise in my main class and pass that to constructor. Everything is working as intended :) Apologies for the not very useful question. – Farrell Coleman Aug 14 '17 at 10:53
  • @EarlLemongrab No need to apologize, the question is fine and well written. The console.log behaviour is indeed very confusing when you don't know what happens there. – Bergi Aug 14 '17 at 11:14

0 Answers0