在我的组件模板中,我在2个地方为同一个Observable调用async
管道。
我应该订阅它并在我的模板中使用返回的数组,或者在模板的多个位置使用async
管道对同一个Observable对性能没有负面影响吗?
答案 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>