Подтвердить что ты не робот

Производительность использования одного и того же наблюдаемого в нескольких местах в шаблоне с асинхронной трубой

В моем шаблоне компонента я звоню в async для того же Observable в 2 местах.

Должен ли я подписаться на него и использовать возвращенный массив в моем шаблоне или используя тэг async для того же Observable в нескольких местах шаблона, не оказывает отрицательного влияния на работу?

4b9b3361

Ответ 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>'
})