为什么在使用Subject或在ngAfterContentInit之后发出组合的可观察对象不更新模板

bub*_*ble 5 subject observable rxjs behaviorsubject angular

我在组件中定义了一个可观察的(result $),并通过异步管道将其显示在其模板上。可观察值是通过CombineLatest将其他2个可观察值(first $,second $)组合而成的。如果其中一个或两个可观察对象发出的时间过早(在我发现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.log('combined obs emitted value');
          return first + second;
        })
      );
   console.log('first and second emit value');
   this.first$.next(2);
   this.second$.next(4);
  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}
Run Code Online (Sandbox Code Playgroud)

执行顺序为:

1.第一和第二发射值

2.ngAfterContentInit

我在这里的假设是,在ngAfterViewInit中,模板已渲染,并且已进行预订。因为可观察对象在此之前发出一个值,所以不会通知组件。这仅意味着结果的可观察对象是冷的(因此,您需要在其发出值之前进行预订)。这两个可观察对象是对象,因此我认为对象是冷可观察对象。它是否正确?

如果我延迟了first $和second $的发射,则一切正常:Component:first $和second $稍后发射@Component({选择器:'my-app',templateUrl:'./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.log('combined obs emitted value');
          return first + second;
        })
      );

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

  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}
Run Code Online (Sandbox Code Playgroud)

现在的订单是:

  1. ngAfterContentInit

  2. 第一和第二发射值

  3. 综合obs发射值

再说一遍,这是因为预订是在可观察对象发出值之前进行的吗?

如果将observables更改为BehaviorSubject,则即使在进行订阅之前发出了值,一切也可以正常工作。这是否意味着BehaviourSubject是可观察的热点?组成部分:作品

@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.log('combined obs emitted value');
          return first + second;
        })
      );


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


  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}
Run Code Online (Sandbox Code Playgroud)

Stackblitz

kct*_*ang 5

问题1:这两个可观察物是对象,所以我认为对象是冷可观察物。它是否正确?

答案这个问题答案这个问题本身很热。该文章介绍了热,冷和科目。

问题2:再说一次,这是因为预订是在可观察对象发出值之前进行的吗?

A2:是的。订阅主题后,您将获得值。您介绍的delay()应该已经花了一些时间才能实现。

为什么?这是因为a BehaviorSubject始终持有一个值并在订阅时发出它,而a Subject不持有一个值,它只是从生产者向当前订户发出值。细节

问题3:这是否意味着BehaviourSubject是热门观察对象?

答:请参阅A1。

很抱歉,如果这样不能直接回答您的问题。我只是想说...在处理Subject和BehaviorSubject时,我并不在乎它们是冷还是热。

相反,我问:“我是否希望观察对象在订阅时始终保持一个值?”。如果是,我使用BehaviorSubject。如果我没事就订阅就没有价值,那就Subject没关系。除了这种差异之外,它们两个都将在订阅后接收发射的值。---取决于您的用例。