Gavin Yap
Gavin Yap

Reputation: 762

How to make a Promise not re-run code when already resolved?

I have a User Model:

export class User extends Serializable{
  id: string; 
  first_name: string; 
  middle_name: string; 
  last_name: string;
  email: string;
  image_url: string;

  // mykeyStore
  static store:StoreDatabase = new StoreDatabase("mykeyStore");


... More code...

and a loadProfile() function to that class which returns a promise.

loadProfile():Dexie.Promise<any>{
    let promise = User.store.get('user')
      .then(
        tuple => {
          // Extract User Data from tuple
          let user_data = tuple && tuple.value

          // Fill User attribute for Tuple's value
          for (var attr in user_data) {
            this[attr] = user_data[attr];
          }
        }); 

    return promise;
}

How can I structure my code, so that calling loadProfile will not always run the then if it is already resolved, by calling the following:

let user = new User();
user.loadProfile().then( () =>
   console.log(user.first_name)
);

Upvotes: 3

Views: 115

Answers (2)

Michał Perłakowski
Michał Perłakowski

Reputation: 92629

Every time you call user.loadProfile(), a new promise is created. Therefore, the code in .then() will always run.

If you want to avoid loading attributes multiple times, you can change your function to this:

loadProfile():Dexie.Promise<any>{
    if (this.promise) return this.promise
    this.promise = User.store.get('user')
      .then(
        tuple => {
          // Extract User Data from tuple
          let user_data = tuple && tuple.value

          // Fill User attribute for Tuple's value
          for (var attr in user_data) {
            this[attr] = user_data[attr];
          }
        }); 

    return this.promise;
}

Then if you call user.loadProfile() when it's already loaded, the code in .then() will be executed immediately.

Upvotes: 2

steppefox
steppefox

Reputation: 1844

In your case, loadProfile will execute inside code again. To avoid that, you need to store the promise in some variable. For example (es6, cuz i don't know typescript well):

// Execute code inside loadProfile and store the promise in some variable
const loadProfilePromise = user.loadProfile();

// Will show Hurray
loadProfilePromise.then(() => console.log('Hurray');

// Will not execute code inside loadProfile again, but will show 'Hurray2'
setTimeout(() => {
    loadProfilePromise.then(() => {
        console.log('Hurray2'));
    });
}, 100);

And also, do not forget to handle exceptions and rejects in promises, and log them ;D

Upvotes: 3

Related Questions