NgrxStore и Angular - используйте асинхронный канал массово или подписывайтесь только один раз в конструкторе

Я начинаю смотреть на ngrx Store, и я вижу удобство использования Angular async pipe. В то же время я не уверен, является ли использование гравитационной асинхронной трубы массово хорошим выбором.

Я делаю простой пример. Предположим, что в том же шаблоне мне нужно показать разные атрибуты объекта (например, Person), который извлекается из Хранилища.

Частью кода шаблона может быть

<div>{{(person$ | async).name}}</div>
<div>{{(person$ | async).address}}</div>
<div>{{(person$ | async).age}}</div>

в то время как конструктор класса компонента

export class MyComponent {
  person$: Observable<Person>;

  constructor(
    private store: Store<ApplicationState>
  ) {
      this.person$ = this.store.select(stateToCurrentPersonSelector);
  }
.....
.....
}

Насколько я понимаю, этот код подразумевает 3 подписки (сделанные в шаблоне через асинхронный канал) на тот же Observable (person$).

Альтернативой было бы определить 1 свойство (person) в MyComponent и иметь только 1 подписку (в конструкторе), которая заполняет свойство, например

export class MyComponent {
  person: Person;

  constructor(
    private store: Store<ApplicationState>
  ) {
      this.store.select(stateToCurrentPersonSelector)
                .subscribe(person => this.person = person);
  }
.....
.....
}

в то время как шаблон использует стандартное связывание свойств (т.е. без асинхронного канала), например

<div>{{person.name}}</div>
<div>{{person.address}}</div>
<div>{{person.age}}</div>

Теперь вопрос

Есть ли разница в производительности между двумя подходами? Является ли массовое использование асинхронной трубы (т.е. Массовым использованием подписки) повлиять на эффективность кода?

Ответы

Ответ 1

Вы также не должны составлять свое приложение как интеллектуальные и презентационные компоненты.

Преимущества:

  • Вся логика buissness на интеллектуальном контроллере.
  • Всего одна подписка
  • Повторное использование
  • Контроллер представления несет только одну ответственность, только для представления данных и не знает, откуда взялись данные. (слабо связанный)

Отвечая на последний вопрос:

Массивное использование асинхронной трубы повлияет на эффективность, поскольку она будет подписаться на каждый асинхронный канал. Вы можете заметить это больше, если вы вызываете http-сервис, потому что он будет вызывать HTTP-запрос для каждого асинхронного канала.

Интеллектуальный компонент

@Component({
  selector: 'app-my',
  template: '
      <app-person [person]="person$ | async"></app-person>
',
  styleUrls: ['./my.component.css']
})
export class MyComponent implements OnInit {

    person$: Observable<Person>;

    constructor(private store: Store<ApplicationState>) {}

    ngOnInit() {
        this.person$ = this.store.select(stateToCurrentPersonSelector);
    }

}

Компонент презентации

@Component({
  selector: 'app-person',
  template: '
    <div>{{person.name}}</div>
    <div>{{person.address}}</div>
    <div>{{person.age}}</div>
',
  styleUrls: ['./my.component.css']
})
export class PersonComponent implements OnInit {

    @Input() person: Person;

    constructor() {}

    ngOnInit() {
    }

}

Для получения дополнительной информации:

Ответ 2

Другая возможность заключается в том, чтобы использовать такую конструкцию:

<div *ngIf="person$ | async as per">
    <div>{{ per.name }}</div>
    <div>{{ per.address }}</div>
    <div>{{ per.age }}</div>
<div>

Хотя для многократно используемых битов кода его можно использовать лучше, используя метод компонент представления.

Обратите внимание, что это работает в угловом 5, не уверен в других версиях.

Ответ 3

Вы можете добавить ".share()" в конец любых наблюдаемых объявлений. Все ваши асинхронные каналы на наблюдаемом затем будут иметь одну и ту же подписку:

this.name$ = Observable.create(observer => {
  console.log("Subscriber!", observer);
  return observer.next("john")
}).delay(2000).share();

this.httpget$ = http.get("https://api.github.com/").share();

Plunkr демонстрирует: https://embed.plnkr.co/HNuq1jUh3vyfR2IuIe4X/