Modermo
Modermo

Reputation: 1992

Setting asynchronous value as a property value after Class instantiation

I would like the value of one of the properties in my class to be an asynchronous value. It almost works; when you call setTimeout, profile.songs is in fact resolved with Promise {<resolved>: Array(100)}.

Except, I want the value (in this case, Array(100)) of the Promise to be the value of property.songs.

Edit: I should add some clarity to the question. The object must be instantiated synchronously i.e. profile.toxicGarbageIsland and profile.spiceUpYourLife are mandatory, and are required for the object to instantiate. The promise value, profile.songs however, is optional, and can come after the object is instantiated.

class Gojira {
  constructor (profile) {
    Object.assign(this, profile)
  }

  static init () {
    let profile = {};

    profile.toxicGarbageIsland = true;
    profile.spiceUpYourLife = false;
    profile.songs = axios.get('https://jsonplaceholder.typicode.com/posts')
      .then(function(response){
        return response.data;   
      }).catch(function (error) {
        console.log(error)
      })

    return new Gojira(profile);
  }
}


let gojiraInstance = Gojira.init();

setTimeout(function(){
  console.log(gojiraInstance)
}, 2000)

N.B. I've removed the promise from the constructor to ensure it's only concern is with returning an object instance, which I've read is best practice.

Upvotes: 2

Views: 86

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370989

Don't assign the promise to profile.songs - instead, simply run the promise, and on resolution, assign the result to profile.songs and call the constructor.

static init() {
  let profile = {};

  profile.toxicGarbageIsland = true;
  profile.spiceUpYourLife = false;
  return axios.get('https://jsonplaceholder.typicode.com/posts')
    .then(function(response) {
      profile.songs = response.data;
      return new Gojira(profile);
    }).catch(function(error) {
      console.log(error)
    });
}

You'll also have to consume it asynchronously:

Gojira.init()
  .then(gojiraInstance => {
    // ...
  });

I'm assuming the constructor requires the profile to be fully set before running. If not, then allow the constructor to accept a Promise as a parameter as well, which then assigns the songs property on resolution, like this:

class Gojira {
  constructor (profile, songsPromise) {
    Object.assign(this, profile);
    if (songsPromise) songsPromise.then(({ data }) => this.songs = data);
  }
  static init () {
    const profile = {};
    profile.toxicGarbageIsland = true;
    profile.spiceUpYourLife = false;
    const songsPromise = axios.get('https://jsonplaceholder.typicode.com/posts')
      .catch(error => console.log(error));
    return new Gojira(profile, songsPromise);
  }
}
const gojiraInstance = Gojira.init();
setTimeout(function(){
  console.log(gojiraInstance)
}, 2000)

Upvotes: 1

Related Questions