NgrxStore 和 Angular - 大量使用异步管道或在构造函数中只订阅一次

Posted

技术标签:

【中文标题】NgrxStore 和 Angular - 大量使用异步管道或在构造函数中只订阅一次【英文标题】:NgrxStore and Angular - Use the async pipe massively or subscribe just once in the constructor 【发布时间】:2017-06-02 03:23:05 【问题描述】:

我开始关注 ngrx Store,我看到了使用 Angular 异步管道的便利。同时我不确定是否大量使用 Angular 异步管道是一个不错的选择。

我举一个简单的例子。假设在同一个模板中,我需要显示从 Store 中检索到的对象(例如 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$)。

另一种方法是在 MyComponent 中定义 1 个属性 (person),并且只有 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>

现在的问题

这两种方法在性能方面有什么不同吗?大量使用异步管道(即大量使用订阅)会影响代码的效率吗?

【问题讨论】:

您可能需要考虑在容器中对“哑”组件的输入使用异步管道。查看example-appPresentational and Container Components 中的组件和容器。 【参考方案1】:

您也不应该将您的应用程序编写为智能和演示组件。

优点:

智能控制器上的所有业务逻辑。 只需订阅一次 可重用性 展示控制器只有一个职责,只展示数据,不知道数据从哪里来。 (松散耦合)

回答最后一个问题:

大量使用异步管道会影响效率,因为它会订阅每个异步管道。如果您正在调用 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() 
    


更多信息请查看:

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.u27zmzf25 http://blog.angular-university.io/angular-2-smart-components-vs-presentation-components-whats-the-difference-when-to-use-each-and-why/

【讨论】:

我很欣赏拆分智能组件和演示组件的价值。出于您提到的所有原因,这很有意义。如果我们只看故事的“代码效率”方面,我是否正确地假设使用一个“异步管道”和许多“属性绑定”比使用“许多异步管道”更有效?提前谢谢 与我想要询问的信息完全相同。非常感谢! 很好的答案,但是在使用带有路由器的子组件时它会有什么用处?【参考方案2】:

另一种可能性是使用这样的构造:

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

虽然对于可重用的代码位,使用表示组件方法可能更好。

请注意这适用于 Angular 5,不确定其他版本。

【讨论】:

我喜欢这个,因为它将智能和演示组件融合到一个代码块中。出于完全相同的原因,我不喜欢这个。 :) 如何在控制器中访问per?我猜现在的方式?【参考方案3】:

您可以在任何可观察声明的末尾添加“.share()”。一个 observable 上的所有异步管道都将共享同一个订阅:

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/

【讨论】:

以上是关于NgrxStore 和 Angular - 大量使用异步管道或在构造函数中只订阅一次的主要内容,如果未能解决你的问题,请参考以下文章

StoreModule.forRoot() 和 StoreModule.forFeature() 有啥区别

NativeScript + ngrx 存储 + 远程开发工具

Ngrx 相对于 Observable Data Services 架构的优势? [关闭]

Angular有哪些地方比Vue更优秀?

Vue-学习。

Angular:使用打开和关闭sidenav(Angular Materials)使div填充剩余的水平空间