服务中的 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我建议使用 .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中的通用列表排序/关键字:订单列表选择器服务排序