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/