Выполнение асинхронного кода - использование Javascript OOP в реагирующем - PullRequest
0 голосов
/ 26 ноября 2018

Я работаю над собственным реактивным проектом, и чтобы упростить манипулирование пользователями, я создал класс User, который подключается к базе данных firebase для получения всей информации о пользователе (например, имя).

Но у меня есть проблема, код запускается асинхронно.Если я хочу сделать:

User.getCurrentUser().alertName(); // Display "undefined"

Функция alertName() запускается перед конструктором класса User, в котором инициализируется имя, поэтому эта строка просто записывает "undefined".

ЗдесьКласс пользователя:

class User {

    uid;
    object;
    name;

    constructor(id){

        firebase.database().ref('/user/'+id).once('value').then( function (snapshot) {

            this.object = snapshot.val();

            this.uid = id;
            this.name = this.object.name;

            console.log("In constructor : " + this.name);
        });
    }

    alertName(){
        console.log("From function : " + this.name);
    }

    static getCurrentUser(){
        let id = firebase.auth().currentUser.uid;
        return new User(id);
    }
}

При попытке сделать:

User.getCurrentUser().alertName();

Журнал консоли:

Из функции: undefined
ИзКонструктор: Джон

Функция выполняется перед конструктором, поэтому, конечно, имя не определено ...

Как это исправить?

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Побочные эффекты в конструкторе можно считать антипаттерном, это относится к асинхронному коду именно потому, что результат не будет доступен сразу после создания класса.

Должно быть представлено обещание:

constructor(id){
    const initPromise = Promise.resolve(firebase.database().ref('/user/'+id).once('value').then( function (snapshot) {...});
}

alertName(){...}

И либо вручную:

const user = User.getCurrentUser();
await user.initPromise;
user.alertName();

Или внутренне:

async alertName(){
  await this.initPromise();
  ...
}

и

const user = User.getCurrentUser();
await user.alertName();

Это тот случай, когда ООП проектированиене имеет особых преимуществ.Поскольку React уже поощряет функциональное программирование, оно может быть более простым без класса.

0 голосов
/ 26 ноября 2018
class User {

    uid;
    object;
    name;

    constructor(id){

        return firebase.database().ref('/user/'+id).once('value').then( function (snapshot) {

            this.object = snapshot.val();

            this.uid = id;
            this.name = this.object.name;
            console.log("In constructor : " + this.name);
            return this;
        });
    }

    alertName(){
        console.log("From function : " + this.name);
    }

    static getCurrentUser(){
        let id = firebase.auth().currentUser.uid;
        return new User(id);
    }

и теперь во время вызова он делает что-то вроде


User.getCurrentUser().then(user => user.alertName());


Итак, что здесь происходит, мы возвращаем обещание от конструктора, который послевызывающая база данных разрешается с uid, name and object, и мы возвращаем это, то есть User из этого обещания.Итак, когда мы сделаем User.getCurrentUser(), мы получим обещание, которое разрешается с фактическим текущим пользователем, а при разрешении мы вызовем alertName метод currentUser.

...