服务中的 Angular 4+ ngOnDestroy() - 销毁 observable

Posted

技术标签:

【中文标题】服务中的 Angular 4+ ngOnDestroy() - 销毁 observable【英文标题】:Angular 4+ ngOnDestroy() in service - destroy observable 【发布时间】:2018-02-04 12:57:23 【问题描述】:

在一个 Angular 应用程序中,我们有一个组件/指令的 ngOnDestroy() 生命周期钩子,我们使用这个钩子来取消订阅 observables。

我想清除/销毁在@injectable() 服务中创建的可观察对象。 我看到一些帖子说ngOnDestroy()也可以在服务中使用。

但是,这是一种好的做法,也是唯一的方法吗?什么时候会调用它? 有人请澄清。

【问题讨论】:

【参考方案1】:

OnDestroy 生命周期挂钩在提供程序中可用。 根据文档:

当指令、管道或服务被销毁时调用的生命周期钩子。

这是example:

@Injectable()
class Service implements OnDestroy 
  ngOnDestroy() 
    console.log('Service destroy')
  


@Component(
  selector: 'foo',
  template: `foo`,
  providers: [Service]
)
export class Foo implements OnDestroy 
  constructor(service: Service) 

  ngOnDestroy() 
    console.log('foo destroy')
  


@Component(
  selector: 'my-app',
  template: `<foo *ngIf="isFoo"></foo>`,
)
export class App 
  isFoo = true;

  constructor() 
    setTimeout(() => 
        this.isFoo = false;
    , 1000)
  

注意上面代码中Service是一个属于Foo组件的实例,所以当Foo被销毁时它可以被销毁。

对于属于根注入器的提供程序,这将在应用程序销毁时发生,这有助于避免多个引导程序(即在测试中)的内存泄漏。

当父注入器的提供者在子组件中订阅时,它不会在组件销毁时被销毁,这是组件在组件ngOnDestroy 中取消订阅的责任(正如另一个答案所解释的那样)。

【讨论】:

class Service implements OnDestroy ?如果在模块级别提供服务,你怎么看这个被调用 implements OnDestroy 不会影响任何内容,但可以添加以确保完整性。它会在模块被销毁时调用,例如appModule.destroy()。这对于多个应用程序初始化可能很有用。 每个使用服务的组件都需要取消订阅吗? Plunker 不适合我,所以这里是 StackBlitz 版本的示例:stackblitz.com/edit/angular-mggk9b 我很难理解这一点。但这次讨论帮助我理解了本地服务和全球服务之间的区别:***.com/questions/50056446/… 我认为是否必须“清理”取决于您的服务范围。【参考方案2】:

在你的服务中创建一个变量

subscriptions: Subscriptions[]=[];

将您的每个订阅推送到数组

this.subscriptions.push(...)

写一个dispose()方法

dispose()
this.subscriptions.forEach(subscription =>subscription.unsubscribe())

在 ngOnDestroy 期间从您的组件调用此方法

ngOnDestroy()
   this.service.dispose();
 

【讨论】:

感谢您的回复。我们是否知道何时调用此 ngOnDestroy。 ? 是的,它说在指令或组件被销毁之前它是一个清理调用。但我只是想了解它是否也适用于服务? 模块卸载时不会清除任何服务 生命周期钩子不适用于@injectables @Aravind 我不确定它们是什么时候介绍的,但they are。【参考方案3】:

我更喜欢这种由 pipable 运算符启用的 takeUntil(onDestroy$) 模式。我喜欢这种模式更简洁、更干净,并且清楚地传达了在执行 OnDestroy 生命周期钩子时终止订阅的意图。

这种模式适用于服务以及订阅注入的 observables 的组件。下面的框架代码应该为您提供足够的详细信息,以便将模式集成到您自己的服务中。想象一下,您正在导入一个名为 InjectedService...的服务...

import  InjectedService  from 'where/it/lives';
import  Injectable, OnDestroy  from '@angular/core';
import  Observable  from 'rxjs/Rx';
import  takeUntil  from 'rxjs/operators';
import  Subject  from 'rxjs/Subject';

@Injectable()
export class MyService implements OnDestroy 

  private onDestroy$ = new Subject<boolean>();

  constructor(
    private injectedService: InjectedService
  ) 
    // Subscribe to service, and automatically unsubscribe upon `ngOnDestroy`
    this.injectedService.observableThing().pipe(
      takeUntil(this.onDestroy$)
    ).subscribe(latestTask => 
      if (latestTask) 
        this.initializeDraftAllocations();
      
    );
  

  ngOnDestroy() 
    this.onDestroy$.next(true);
    this.onDestroy$.complete();
  

何时/如何取消订阅的主题在此处广泛讨论:Angular/RxJs When should I unsubscribe from `Subscription`

【讨论】:

【参考方案4】:

澄清一下 - 您无需销毁 Observables,只需销毁对它们的订阅即可。

似乎其他人已经指出您现在也可以将ngOnDestroy 与服务一起使用。链接:https://angular.io/api/core/OnDestroy

【讨论】:

能否详细说明一下【参考方案5】:

使用令牌时要注意

在尝试使我的应用程序尽可能模块化时,我经常使用提供者令牌来为组件提供服务。似乎这些没有得到他们的ngOnDestroy 方法调用:-(

例如。

export const PAYMENTPANEL_SERVICE = new InjectionToken<PaymentPanelService>('PAYMENTPANEL_SERVICE');

在组件中有提供程序部分:

 
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 

我的ShopPaymentPanelService 没有在处置组件时调用其ngOnDestroy 方法。我刚刚发现了这一点!

解决方法是与useExisting 一起提供服务。

[
   ShopPaymentPanelService,

   
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   
]

当我这样做时,ngOnDispose 被按预期调用。

不确定这是否是错误,但非常意外。

【讨论】:

很好的提示!我想知道为什么它在我的情况下不起作用(我使用抽象类接口作为具体实现的标记)。【参考方案6】:

在您的服务中创建一个变量:

private subscriptions$ = new Subscription();

在构造函数中(或在 ngOnInit 生命周期钩子中)将每个订阅添加到 observable

ngOnInit() 
  this.subscriptions.add(...)
  this.subscriptions.add(...)

在销毁时从您的组件调用此方法以取消订阅所有订阅和子订阅。

ngOnDestroy()
   this.subsriptions$.unsubscribe();

【讨论】:

我认为 $ 前缀通常用于可观察对象,但不用于订阅。我遵循的约定:rat 是 Rat 对象,rats 是 Rat[](或 List),rat$ 是 Observable。无论如何,恕我直言,这是最好的答案。【参考方案7】:

我建议使用 .pipe(take(1)).subscribe()。避免设置持续订阅。

【讨论】:

以上是关于服务中的 Angular 4+ ngOnDestroy() - 销毁 observable的主要内容,如果未能解决你的问题,请参考以下文章

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序

html Angular 1.4.x中的通用列表排序/关键字:订单列表选择器服务排序