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

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

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

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

【问题讨论】:

    标签: angular rxjs observable angular-services


    【解决方案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
    • 我很难理解这一点。但这次讨论帮助我理解了本地服务和全球服务之间的区别:stackoverflow.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()。避免设置持续订阅。

      【讨论】:

        猜你喜欢
        • 2020-02-14
        • 1970-01-01
        • 1970-01-01
        • 2019-01-28
        • 1970-01-01
        • 2019-07-18
        • 2018-02-14
        • 2021-01-09
        • 1970-01-01
        相关资源
        最近更新 更多