Производительность использования одного и того же наблюдаемого в нескольких местах в шаблоне с асинхронной трубой
В моем шаблоне компонента я звоню в async
для того же Observable в 2 местах.
Должен ли я подписаться на него и использовать возвращенный массив в моем шаблоне или используя тэг async
для того же Observable в нескольких местах шаблона, не оказывает отрицательного влияния на работу?
Ответы
Ответ 1
Каждое использование observable$ | async
создаст новую подписку (и, следовательно, отдельный поток) для данного observable$
- если этот наблюдаемый содержит части с тяжелыми вычислениями или остальными вызовами, эти вычисления и остаточные вызовы выполняются индивидуально для каждого async
- так да - это может иметь последствия для производительности.
Однако это легко фиксируется, расширяя observable$
с помощью .share()
, чтобы иметь общий поток среди всех подписчиков и выполнять все эти вещи только один раз для всех подписчиков.
Не забудьте добавить share
-оператор с import "rxjs/add/operator/share";
Причина, по которой async-pipe не использует подписки по умолчанию, - это просто гибкость и простота использования: простой .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
}
Ответ 2
Еще один способ избежать нескольких подписок - использовать упаковку *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(", "));
}
Это также круто, потому что немного очищает шаблон.
Ответ 3
Мне повезло с .shareReplay из 'rxjs/add/operator/shareReplay', который является очень новым (https://github.com/ReactiveX/rxjs/pull/2443)
Мне также повезло с .publishReplay.refCount(1) (Angular 2 + rxjs: async pipe с оператором .share())
Я честно не уверен в различии между двумя стратегиями. Комментарии в PR для shareReplay предполагают, что может быть больше риска утечек памяти подписок, если они не реализованы правильно, поэтому я могу пойти с .publishReplay.refCount(1) на данный момент.
Ответ 4
Решение, предоставленное выше @Hinrich, очень хорошо, но иногда вы блокируетесь, потому что хотите использовать несколько наблюдаемых в шаблоне, в этом случае есть простое решение, подобное этому:
@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>'
})