Асинхронный метод не возвращает значение и зависает

#angular #typescript #async-await #firebase-authentication #google-cloud-firestore

#angular #typescript #async-ожидание #firebase-аутентификация #google-облако-firestore

Вопрос:

Я хочу получить пользовательские данные зарегистрированного пользователя из Google Firebase. Для этого я написал два метода; один получает authState , а другой получает UserInfo , содержащий более подробную информацию.

Это два метода, реализованные в службе, которая вызывается UserService :

 constructor(private fireStore: AngularFirestore, private fireAuth: AngularFireAuth) {
}

public async getAuthorizedUser(): Promise<UserInfo> {
  console.log('Awaiting Promise');
  const user: firebase.User = await this.fireAuth.authState.toPromise();
  console.log('User', user);
  return this.getUserInfo(user.uid);
}

private async getUserInfo(uid: string): Promise<UserInfo> {
  return this.fireStore.collection('users', ref => ref.where('uid', '==', uid))
             .get()
             .pipe(
               map((item: firebase.firestore.QuerySnapshot) => new UserInfo(item.docs[0].data(), item.docs[0].id))).toPromise();
}
  

Я вызываю getAuthorizedUser метод из обработчика событий button, реализованного в компоненте.
HTML-элемент кнопки выглядит следующим образом:

 <button mat-button (click)="test()">test</button>
  

и test() метод реализован как:

 async test() {
  console.log('Starting Test');
  const testVariable = await this.userService.getAuthorizedUser();
  console.log('Test', testVariable);
}
  

Кроме того, userService это введенная зависимость UserService .

Консоль показывает:

Запуск теста
в ожидании обещания

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

Тест

или

Пользователь {…}

или оба.

Что не так?

Редактировать — и частичный ответ:

После еще нескольких исследований в Google, если найдено на angularfirebase.com что authState следует вызывать как

 const user: firebase.User = await this.fireAuth.authState.pipe(first()).toPromise();
  

Однако это меня смущает, потому что я использовал приведенный ниже код, прежде чем решил перейти на наблюдаемые вместо обычных переменных. Код сработал, однако я не вижу никаких признаков какого-либо массива, который возвращается authState

 this.fireAuth.authState.subscribe((user: firebase.User) => {
  if (user) {
    this.getUserData(user.uid);
  }
});
  

Что происходит и почему мое решение работает?

Комментарии:

1. Что произойдет, если вы сделаете: const user = await this.fireAuth.authState.pipe(first()).toPromise(); ?

2. Интересно, что это работает, как я также узнал несколько минут назад. Но зачем мне нужно использовать pipe(first()) ? Я обновил вопрос, не стесняйтесь ответить на эту проблему

Ответ №1:

toPromise() создает обещание, которое будет разрешено по завершении потока.

Поэтому, если this.fireAuth.authState никогда не завершается, но выдает значения, вы можете использовать first оператор для создания потока, который завершается после первого переданного значения. Таким образом, обещание выполняется.

Обработчик подписки, с другой стороны, вызывается для каждого значения.