【问题标题】:angular2 destroying subscriptions on view destroyangular2在视图销毁时销毁订阅
【发布时间】:2016-12-06 22:05:12
【问题描述】:

我有一个“appService”,用于处理所有组件(表单、导航等)之间的交互。

我的服务有许多组件订阅的事件发射器(结果显示、元素选择、表单发布等)。

当显示一个新视图时,它会订阅它需要的 appService 事件。现在的问题是当我导航到另一个视图(表单)时,不再需要的视图被破坏,但它的订阅仍然被调用......!我发现引用所有订阅和明确取消订阅对于一项简单的任务来说是一个巨大的样板。我究竟做错了什么?如何简化这个?

示例代码:

export class VendorsForm {
    constructor(private appService: AppServiceMain)
    {
            this.appService.onSearchResultSelected$.subscribe((selectedEntity) => {
            //detailed view of this item
            this.model = selectedEntity;
            this.appService.setFormIsShowingDetail();
        })
    });

    }
}

现在在另一个组件中:

export class CustomersForm {
    constructor(private appService: AppServiceMain)
    {
            this.appService.onSearchResultSelected$.subscribe((selectedEntity) => {
            //detailed view of this item
            this.model = selectedEntity; this.appService.setFormIsShowingDetail();
        })
    });

    }
}

作为参考,这里是服务和事件调用组件:

export class AppServiceMain {
    public onSearchResultSelected$: EventEmitter<IEntity>;
        setSelectedEntity(ent: IEntity)
        {
            this.formstate = states.EntitySelected;
            this.onSearchResultSelected$.emit(ent);
        }

事件调用组件

export class ResultsComponent { 
    rowDblClick(ev$)
    {
        this.appService.setSelectedEntity(ev$.data);
    }

如果我愿意,我确实知道如何删除这些订阅。问题是我的表单非常大而且功能强大,而且我有大量的非标准参考,难道没有办法在视图被破坏时自动停止收听吗?我发现手动销毁所有这些非常容易出错。

【问题讨论】:

  • 小备注:我的ResultsComponent 和appService 都始终是活动的并且是单个实例
  • 您能否说明为什么实现ngOnDestroy 方法对您不起作用?如果您错过了:OnDestroy

标签: angular observable subscription eventemitter ondestroy


【解决方案1】:

如果你强制订阅,那么也强制取消订阅

 this.someSubscription = this.appService.onSearchResultSelected$.subscribe((selectedEntity) =>

ngOnDestroy() {
  this.someSubscription.unsubscribe();
}

另见how to unsubscribe several subscriber in angular 2

【讨论】:

  • 感谢 Günter,实际上这就是我现在正在做的事情......我得到了一个数组中所有订阅的句柄......但我讨厌那样做......我已经还看到有一种方法可以使用“异步管道”使其自动化,但也很糟糕......我觉得 angular2 正在推动最奇怪的模式......你如何处理这些东西?也许这种方法不适合应用程序流管理?
  • 我认为| async 和取消订阅都没有问题。
  • 我会标记你的答案 - 只是说这个语法是 CODE SMELL
【解决方案2】:

您不需要拥有大量订阅。使用RxJS.SubjecttakeUntil 组合像老板一样处理订阅:

import {Subject} from "rxjs/Subject";

@Component(
    {
        moduleId: __moduleName,
        selector: 'my-view',
        templateUrl: '../views/view-route.view.html',
    }
)
export class ViewRouteComponent implements OnDestroy
{
    componentDestroyed$: Subject<boolean> = new Subject();

    constructor(protected titleService: TitleService)
    {
        this.titleService.emitter1$
            .takeUntil(this.componentDestroyed$)
            .subscribe(
            (data: any) =>
            {
                // ... do something 1
            }
        );

        this.titleService.emitter2$
            .takeUntil(this.componentDestroyed$)
            .subscribe(
            (data: any) =>
            {
                // ... do something 2
            }
        );

        // ...

        this.titleService.emitterN$
            .takeUntil(this.componentDestroyed$)
            .subscribe(
            (data: any) =>
            {
                // ... do something N
            }
        );
    }

    ngOnDestroy()
    {
        this.componentDestroyed$.next(true);
        this.componentDestroyed$.complete();
    }
}

【讨论】:

    【解决方案3】:

    我的做法是:

    this.subscriptions.push( this.appService.onSearchResultSelected$.subscribe((selectedEntity) => {}));
    
    ngOnDestroy() {
      this.subscriptions.forEach((subscription) => {
            subscription.unsubscribe();
        });
    }
    

    这种方式可以处理n个订阅,每次使用订阅时只需要推送即可。

    这是最简单、最简单的执行方式。

    【讨论】:

      猜你喜欢
      • 2014-04-02
      • 2013-04-16
      • 2016-02-02
      • 1970-01-01
      • 2019-12-08
      • 2022-01-18
      • 1970-01-01
      • 2018-02-13
      • 2018-02-22
      相关资源
      最近更新 更多