Почему комбинированные наблюдаемые не обновляют шаблон при использовании Subject или если они испускаются после ngAfterContentInit

Я определяю наблюдаемый объект (result$) в компоненте и отображаю его в его шаблоне через асинхронный канал. Наблюдаемый объект представляет собой комбинацию двух других наблюдаемых (первый $, второй $) через combLatest. Если один из наблюдаемых или оба излучаются слишком рано (до того, как я нашел ngAfterContentInit), результирующий наблюдаемый не будет излучать значение.

Компонент: не работает

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();

  constructor() {}

  ngOnInit(){
      this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          // This is not printed to the console
          console.info('combined obs emitted value');
          return first + second;
        })
      );
   console.info('first and second emit value');
   this.first$.next(2);
   this.second$.next(4);
  }

  ngAfterContentInit() {
      console.info('ngAfterContentInit');
  }
}

Порядок выполнения такой:

1.первое и второе значение излучения

2.ngAfterContentInit

Мое предположение здесь заключается в том, что в ngAfterViewInit шаблон был отрендерен и подписки были сделаны. Поскольку наблюдаемые выдают значение перед этим, компонент не уведомляется. Это может означать только то, что полученный наблюдаемый объект является холодным (поэтому вам необходимо подписаться, прежде чем он выдаст значение). 2 наблюдаемых являются субъектами, поэтому я предполагаю, что субъекты являются холодными наблюдаемыми. Это правильно?

Если я задержу выпуск first$ и second$, все работает: Компонент: first$ и second$ выпускаются позже @Компонент({ селектор: 'мое-приложение', Url-шаблона: './app.component.html', styleUrls: [ './app.component.css' ] }) экспортный класс AppComponent {

result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();

  constructor() {}

  ngOnInit(){

      this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          console.info('combined obs emitted value');
          return first + second;
        })
      );

    // Solution 1: add timeout
    setTimeout(() => {
      console.info('first and second emit value');
      this.first$.next(2);
      this.second$.next(4);
    })

  }

  ngAfterContentInit() {
      console.info('ngAfterContentInit');
  }
}

Порядок сейчас такой:

  1. нгафтерконтентинит

  2. первое и второе значение эмиссии

  3. комбинированное значение излучения наблюдений

Итак, опять же, это потому, что подписка сделана до того, как наблюдаемые выдают значение?

Если я изменю observables на BehaviorSubject, все тоже будет работать, даже если значения выдаются до того, как произойдет подписка. Означает ли это, что BehaviourSubjects являются горячими наблюдаемыми? Компонент: работает

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

result$: Observable<number>;
first$ = new BehaviorSubject<number>(0);
second$ = new BehaviorSubject<number>(0);

  constructor() {

  }

  ngOnInit(){

this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          // This is not printed to the console
          console.info('combined obs emitted value');
          return first + second;
        })
      );


  console.info('first and second emit value');
   this.first$.next(2);
   this.second$.next(4);


  }

  ngAfterContentInit() {
      console.info('ngAfterContentInit');
  }
}

Stackblitz

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
7
0
1 257
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Q1: 2 наблюдаемых — это Субъекты, поэтому я предполагаю, что субъекты — это холодные наблюдаемые. Это правильно?

A1: ответ на этот вопрос говорит, что тема сама по себе горячая. Этот статья описывает горячие, холодные и предметы.

Q2: Итак, опять же, это потому, что подписка сделана до того, как наблюдаемые выдают значение?

А2: Да. Подписка на Subject получит значения ПОСЛЕ того, как вы подпишетесь. Введенная вами функция delay() должна была дать время для этого.

Почему? Это связано с тем, что BehaviorSubject всегда хранит значение и передает его при подписке, в то время как Subject не содержит значения, а просто передает значения от производителя текущим подписчикам. Подробности.

Q3: Означает ли это, что BehaviourSubjects являются горячими наблюдаемыми?

О: См. А1.

Извините, если это не отвечает на ваш вопрос напрямую. Я просто пытаюсь сказать, что... имея дело с Subject и BehaviorSubject, мне все равно, горячие они или холодные.

Вместо этого я спрашиваю: «Хочу ли я, чтобы наблюдаемые всегда сохраняли значение, когда я подписываюсь?». Если да, я использую BehaviorSubject. Если у меня все в порядке с отсутствием ценности при подписке, то Subject в порядке. Помимо этой разницы, оба они будут получать выпущенные значения после подписки. --- зависит от вашего варианта использования.

Субъекты горячие, но любые производные наблюдаемые с оператором канала, такие как this result$ observable, холодные и ничего не делают, пока на них не подписаны.

Adrian Brand 07.02.2019 04:44

@AdrianBrand, если это правильно, почему выполнение this.result$ = this.first$ не обновляет шаблон?

MartaGalve 07.02.2019 05:06

потому что first$ уже сгенерирован и обновит шаблон только в том случае, если он будет сгенерирован после того, как он будет назначен свойству, за которым наблюдает асинхронный канал.

Adrian Brand 07.02.2019 05:17

Используйте BehaviorSubjects вместо Subjects

https://stackblitz.com/edit/angular-4gnxto?file=src/app/app.component.ts

Асинхронный канал подписывается после отправки Субъектов. BehaviorSubjects дают самый последний результат, когда вы подписываетесь, Subjects дают вам значение только тогда, когда они испускают.

Когда асинхронный канал подписывается на наблюдаемый результат $, созданный с помощью combLatest, он не будет выдавать никакого значения от объектов, которые уже были отправлены, он будет использовать combLatest только для субъектов, которые отправляются после создания подписки.

Посмотрите, как в этом StackBtitz

https://stackblitz.com/edit/angular-eb7dge?file=src/app/app.component.ts

Если вы нажмете кнопку «Emit», значения будут отправлены после того, как асинхронный канал сделал подписку.

Другие вопросы по теме