Угловой Подождите, пока наблюдаемый завершится, прежде чем запускать другой наблюдаемый

#angular #observable

Вопрос:

У меня есть два наблюдаемых :

 constructor(
    private afAuth:AngularFireAuth,
    private db:AngularFireDatabase
    ) {
      
    this.afAuth.authState.subscribe(x=> 
      {
        this.userId=x?.uid;
        console.log(this.userId);
      });
      
      console.log(this.userId);
      this.db.list('users/' this.userId '/movies-favourited').valueChanges().subscribe(data=>{
        this.favouriteList=data;
      });
   }
 

Как мне убедиться, что я получу идентификатор пользователя в первом наблюдаемом, прежде чем получать список во втором наблюдаемом?

Ответ №1:

Правильный способ сделать это-использовать switchMap , как показано ниже:

 this.afAuth.authState.pipe(
    switchMap(user => {
        if(user) {
            this.userId = user.uid;
            this.db.list('users/' this.userId '/movies-favourited')
                .valueChanges().subscribe(data => {
                    this.favouriteList = data;
                });
        }
    })
);
 

Вы можете прочитать больше об этом switchMap здесь.

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

1. Также вы можете использовать оператор объединения rxjs, learnrxjs.io/learn-rxjs/operators/combination/concat

Ответ №2:

Вы можете либо заменить первое наблюдаемое на обещание

или

Вы можете поместить второе наблюдаемое внутри первого, как это:

 this.afAuth.authState.subscribe(x=> 
  {
    this.userId=x?.uid;
    console.log(this.userId);
  this.db.list('users/' this.userId '/movies-favourited').valueChanges().subscribe(data=>{
    this.favouriteList=data;
    });
  });
 

Ответ №3:

Как только первый наблюдаемый объект успешно получит данные, подписавшись, он подпишется на второй наблюдаемый объект, который решит вашу проблему.

 constructor(
    private afAuth: AngularFireAuth,
    private db: AngularFireDatabase
) {
    this.afAuth.authState.subscribe(x => {
        this.userId = x?.uid;
        console.log(this.userId);
        this.db.list('users/'   this.userId   '/movies-favourited').valueChanges().subscribe(data => {
            this.favouriteList = data;
        });
        console.log(this.userId);
    });
}
 

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

1. Можете ли вы объяснить, почему и какие подходы являются лучшими ?

2. Внутренняя подписка остается живой и может неожиданно сработать (каждый раз, когда срабатывает внешняя подписка, вы создаете новую внутреннюю подписку). Этот подход действительно укусит вас в более сложных сценариях. Вы действительно хотите «подключить» наблюдаемые объекты с помощью соответствующих операторов rxjs, таких как switchmap, чтобы в итоге получить только одну подписку. Убийство внешнего тогда также убьет » внутреннего’.

Ответ №4:

Это должно быть решением вашей задачи.

 this.afAuth.authState
                .subscribe(
                    (x: any) => {
                        this.userId = x?.uid;
                        if (x.uid) {
                            this.db.list('users/'   this.userId   '/movies-favourited').valueChanges()
                                .subscribe(
                                    (data: any) => {
                                        this.favouriteList = data;
                                    },
                                    (error) => {
                                        console.log(error);
                                    });
                        }
    
                    },
                    (error) => {
                        console.log(error);
                    }
                );
 

Дополнительные предложения по оптимизации кода:

  1. Подумайте о том, чтобы поместить свой код в жизненный цикл ngOnInit() вместо конструктора.
  2. Определите типы данных ваших переменных » x » и «данные».
  3. Не забудьте отписаться.
  4. Как-то справляйтесь со своими ошибками.