使用异步管道在模板中的多个位置使用相同的observable的性能

时间:2016-11-22 12:42:00

标签: angular rxjs

在我的组件模板中,我在2个地方为同一个Observable调用async管道。

我应该订阅它并在我的模板中使用返回的数组,或者在模板的多个位置使用async管道对同一个Observable对性能没有负面影响吗?

5 个答案:

答案 0 :(得分:104)

observable$ | async的每次使用都会为给定的observable$创建一个新的订阅(以及一个单独的流) - 如果这个可观察的部分包含重度计算或休息调用的部分,那些计算和休息 - 每个async都会单独执行调用 - 所以是的 - 这个可以具有性能影响。

然而,通过observable$扩展.share(),可以轻松修复,在所有订阅者中拥有共享流,并为所有订阅者执行所有这些操作。 不要忘记使用share

添加import "rxjs/add/operator/share"; - 运算符

默认情况下,异步管道不共享订阅的原因只是灵活性和易用性:简单的.share()编写比创建一个全新的流要快得多,如果它们是默认情况下共享。

这是一个简单的例子

@Component({
    selector: "some-comp",
    template: `
        Sub1: {{squareData$ | async}}<br>
        Sub2: {{squareData$ | async}}<br>
        Sub3: {{squareData$ | async}}
    `
})
export class SomeComponent {
    squareData$: Observable<string> = Observable.range(0, 10)
        .map(x => x * x)
        .do(x => console.log(`CalculationResult: ${x}`)
        .toArray()
        .map(squares => squares.join(", "))
        .share();  // remove this line and the console will log every result 3 times instead of 1
}

答案 1 :(得分:12)

避免多个订阅的另一种方法是使用包装*ngIf="obs$ | async as someName"。使用olsn的例子

    @Component({
        selector: "some-comp",
        template: `
          <ng-container *ngIf="squareData$ | async as squareData">
            Sub1: {{squareData}}<br>
            Sub2: {{squareData}}<br>
            Sub3: {{squareData}}
          </ng-container>`
    })
    export class SomeComponent {
        squareData$: Observable<string> = Observable.range(0, 10)
            .map(x => x * x)
            .do(x => console.log(`CalculationResult: ${x}`)
            .toArray()
            .map(squares => squares.join(", "));

    }

它也很酷,因为它也清除了模板。

答案 2 :(得分:2)

我从'rxjs / add / operator / shareReplay'中获得了很好的运气。这是非常新的(https://github.com/ReactiveX/rxjs/pull/2443

我也很幸运.publishReplay.refCount(1)(Angular 2 + rxjs: async pipe with .share() operator

老实说,我不确定两种策略之间的区别。针对shareReplay的PR中的注释表明,如果没有正确实现,可能会有更多的订阅内存泄漏风险,所以我现在可能会使用.publishReplay.refCount(1)。

答案 3 :(得分:0)

@Hinrich上面提供的解决方案非常好,但是有时您会被阻止,因为您想在模板中使用多个可观察对象,在这种情况下,有一个简单的解决方案(它对于像ngrx选择器这样的热可观察对象都适用,但是对于像http请求这样的寒冷现象来说可能不是很好):

    @Component({
    selector: "some-comp",
    template: `
      <ng-container *ngIf="{ book: squareData$ | async, user: otherData$ | async} as data">
        Sub1: {{data.squareData}}<br>
        Sub2: {{data.otherData}}<br>
      </ng-container>`
})

答案 4 :(得分:0)

我们使用@Hinrich解决方案,但使用combineLatest()来代替多个可观察对象的@pegaltier解决方案。

this.data$ = combineLatest(book$, user$)
  .pipe(
    map(([book, user]) => {
      return (book && user) ? { book, user } : undefined;
    }),
  );
<ng-container *ngIf="data$ | async as data">
  {{ data.book }} {{ data.user }}
</ng-container>