带有行为主题和异步管道的Rxjs share()运算符-Angular

时间:2018-10-10 14:43:36

标签: angular rxjs

我有一个BehaviorSubject,可观察性地将其消耗掉:

testForStack$: Observable<boolean>;

ngOnInit(){
    const bs = new BehaviorSubject(true);
    this.testForStack$ = bs
      .asObservable()
      .do(t => console.log('subscribed'))
      .share();
}

此可观察对象通过模板中的三个异步管道进行管道传输:

Sub1: {{testForStack$ | async}}<br>
Sub2: {{testForStack$ | async}}<br>
Sub3: {{testForStack$ | async}}

问题是只有第一个(Sub1)的值为true

Sub1: true
Sub2: 
Sub3:

如果我删除了.share(),则所有三个值都将获得true值,但这会导致多个订阅问题。

是否有任何关于为什么使用BehaviorSubject导致此行为的想法?它被用作观察对象,因此我认为上面的代码可以正常工作。

这也与此答案类似:

https://stackoverflow.com/a/40819423/4912604

2 个答案:

答案 0 :(得分:4)

这是正确的行为。 share()运算符仅对其父级保留一个订阅,而BehaviorSubject仅在订阅时发出其值。

这意味着,当您使用第一个{{testForStack$ | async}}时,它会在链的末尾订阅share(),后者会订阅其父项,从而导致订阅源BehaviorSubject发出立即值。

但是,第二个和所有连续的{{testForStack$ | async}}订阅了share(),而该shareReplay(1)已经订阅了其父项,并且不再进行订阅,因此没有任何将源值推送给这些观察者的功能。 / p>

一个简单的解决方案是使用publishReplay(1).refCount()(取决于您的RxJS版本),由于这些问题(或它的可等效的问题),您可能应该使用tf.top_k

答案 1 :(得分:1)

不要使用共享运算符。而是这样做:

<ng-container *ngIf="testForStack$ | async as testForStack">

  Sub1: {{ testForStack }}
  Sub2: {{ testForStack }} 
  Sub3: {{ testForStack }}

</ng-container>

还有许多其他方法,例如,如果您不喜欢使用* ngIf,则可以对使用ngTemplateOutlet的模板使用相同的方法。这种方法允许您以相同的方式创建别名变量:

<ng-template let-testForStack [ngTemplateOutletContext]="{ $implicit: testForStack$ | async }" [ngTemplateOutlet]="selfie" #selfie>

  Sub1: {{ testForStack }}
  Sub2: {{ testForStack }} 
  Sub3: {{ testForStack }}

</ng-template>

ng-template代码是自引用的(有效),未经完全测试,但“应”起作用,并且避免使用* ngIf

在此处了解更多信息:https://nitayneeman.com/posts/using-single-subscription-for-multiple-async-pipes-in-angular/