是否有可以在组件内使用的等效异步管道?

Posted

技术标签:

【中文标题】是否有可以在组件内使用的等效异步管道?【英文标题】:is there an equivalent of async pipe that you can use inside a component? 【发布时间】:2017-07-19 17:56:57 【问题描述】:

是否存在与async 管道等效的东西,我可以在这样的组件中使用它

   @Component(
      selector: 'my-component',
    )

    export class myComponent 

      myObservable$: Observable<string>;

      method() 
        doSomething(this.myObservable$);
        // here I would like to access directly the current string value of
        // myObservable$ without having to subscribe 
      
    

【问题讨论】:

您能稍微描述一下这个案例吗?因为通常没有真正的需要,所以任何数据转换都应该作为流可写。 【参考方案1】:

你必须问自己:你想通过避免subscribe() 调用来实现什么?我的猜测是,您想防止保留订阅并不得不手动取消订阅。

如果是这种情况,你只需要确保你得到一个完整的 Observable。那么以后就不需要退订了。您可以将任何 Observable(有限或无限)转换为最终完成的。

这是您的案例的示例:

  method() 
    this.myObservable$.take(1).subscribe(
      val => doSomething(val)
    );
  

正确的方法实际上取决于你的 observable 做了什么以及你想用这个值做什么。例如,Angular2 http 调用自行完成,no need to unsubscribe!

或者,如果你想为你的 observable 中的每个新值调用 doSomething,上述解决方案将不适合,因为你只获得第一个值,然后 observable 完成。正如我所说,这归结为问题的背景。

【讨论】:

【参考方案2】:

不,没有。您需要手动订阅和手动取消订阅以避免内存泄漏。

对于简单的订阅,您可能会很想这样做:

@Component(
  selector: 'my-component',
)
export class myComponent implements OnInit, OnDestroy 
  public myObservable$: Observable<string>;
  private myObservableSub: Subscription;

  ngOnInit() 
    this.myObservableSub = this
      .myObservable$
      .subscribe(_ => 
        // do something
      );
  

  ngOnDestroy() 
    this.myObservableSub();
  

但是如果你有很多订阅呢? 您是否应该这样做:

@Component(
  selector: 'my-component',
)
export class myComponent implements OnInit, OnDestroy 
  public myObservable1$: Observable<string>;
  private myObservableSub1: Subscription;

  public myObservable2$: Observable<string>;
  private myObservableSub2: Subscription;

  public myObservable3$: Observable<string>;
  private myObservableSub3: Subscription;

  ngOnInit() 
    this.myObservableSub1 = this
      .myObservable1$
      .subscribe(_ => 
        // do something
      );

    this.myObservableSub2 = this
      .myObservable2$
      .subscribe(_ => 
        // do something
      );

    this.myObservableSub3 = this
      .myObservable3$
      .subscribe(_ => 
        // do something
      );
  

  ngOnDestroy() 
    this.myObservableSub1();
    this.myObservableSub2();
    this.myObservableSub3();
  


**答案是不**

更新回复 (16/11/20)

在原始答案中(请参阅此编辑后),我建议使用 take until 但这会强制您创建一个主题并在组件被销毁时触发一个事件。虽然这背后的想法很好,但在我们订阅流的所有组件中放入相当多的样板。

除此之外,我们可以创建一个自定义运算符,我们可以调用 takeUntilDestroyed 并执行以下操作:

@Component(
  selector: 'my-component',
)
export class myComponent implements OnInit, OnDestroy 
  public myObservable1$: Observable<string>; // define your observable

  public myObservable2$: Observable<string>; // define your observable

  public myObservable3$: Observable<string>; // define your observable

  ngOnInit() 
    this
      .myObservable1$
      .pipe(takeUntilDestroyed(this))
      .subscribe(_ => 
        // do something
      );

    this.myObservableSub2 = this
      .myObservable2$
      .pipe(takeUntilDestroyed(this))
      .subscribe(_ => 
        // do something
      );

    this.myObservableSub3 = this
      .myObservable3$
      .pipe(takeUntilDestroyed(this))
      .subscribe(_ => 
        // do something
      );
  

  ngOnDestroy() 

这个自定义操作符的实现可以在这里找到:https://github.com/cloudnc/ngx-sub-form/blob/1115b21a007f72c54b521b3bed7c40051302145a/projects/ngx-sub-form/src/lib/shared/ngx-sub-form-utils.ts#L145-L148

原始回复

您应该执行以下操作:

@Component(
  selector: 'my-component',
)
export class myComponent implements OnInit, OnDestroy 
  private componentDestroyed$ = new Subject<void>();

  public myObservable1$: Observable<string>;
  public myObservable2$: Observable<string>;
  public myObservable3$: Observable<string>;

  ngOnInit() 
    this
      .myObservable1$
      .takeUntil(componentDestroyed$)
      .subscribe(_ => 
        // do something
      );

    this
      .myObservable2$
      .takeUntil(componentDestroyed$)
      .subscribe(_ => 
        // do something
      );

    this
      .myObservable3$
      .takeUntil(componentDestroyed$)
      .subscribe(_ => 
        // do something
      );
  

  ngOnDestroy() 
    this.componentDestroyed$.next();
    this.componentDestroyed$.complete();
  

如果您想了解更多相关信息,请查看 Ben Lesh 的一篇精彩文章:https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87

编辑: 感谢@olsn,我编辑了我的答案并添加了next 行,因为确实完整并不会阻止其他流。

我创建了一个小 Plunkr 来演示该行为:https://plnkr.co/edit/dcueDqUgpqgYimxEAGUn?p=preview

【讨论】:

您的this.componentDestroyed$.complete() 不会停止任何流,您需要调用.next(),因为complete 只会完成流,但不会发出任何其他流可以响应的数据。 @olsn 谢谢,我编辑了帖子并引用了你的答案! takeUntil 的示例解决了我遇到的导致我提出这个问题的问题。【参考方案3】:

如果您在Component 或可以访问ChangeDetectorRef 的地方,您可以执行以下小技巧:

@Component(
...
  providers: [AsyncPipe]
)
export class ExampleComponent 
  app$ = this.sandbox.allApps$;
  apps = this.pipeAsync.transform(this.app$);

  contructor(
    protected pipeAsync: AsyncPipe,
    protected sandbox: AppAppsSandbox
  ) 

这假定访问名为AppAppsSandbox 的服务,但Observable app$ 可以来自任何地方,这是一种方便的解包方式。

【讨论】:

【参考方案4】:

实现目标的唯一方法(不使用订阅)是使用 BehaviorSubject,它有一个方法 getValue()。 Observables 和 BehaviousSubjects 之间存在一些差异(您可以在 documentation 中找到它们)。

var subject = new Rx.BehaviorSubject(current_subject_value);
subject.getValue()

然而有一些 *** 争论为什么你不应该使用 getValue 方法,而是使用订阅...然而有一个 observable take 运算符将完成可观察序列(因此不必管理订阅)

this.myObservable$.take(1).subscribe()

【讨论】:

【参考方案5】:

你可以使用我的图书馆。您可以创建 useReader 挂钩并将其包装在 AsyncPipe 组件中。看看例子。 https://www.npmjs.com/package/reactivex-react

【讨论】:

以上是关于是否有可以在组件内使用的等效异步管道?的主要内容,如果未能解决你的问题,请参考以下文章

角度-知道模板渲染何时完成-使用异步管道

ngFor 块内模板中的异步管道触发 http GET 调用循环

是否可以将 kubeflow 组件与 tensorflow 扩展组件混合使用?

从服务返回的 Observable 的单元测试值(使用异步管道)

Vue中router路由异步加载组件-优化性能

Angular - 在服务和组件中使用管道