【问题标题】:Disposing of observables in dynamically instantiated Angular2 services在动态实例化的 Angular2 服务中处理 observables
【发布时间】:2016-07-22 16:51:52
【问题描述】:

我有一个 Angular2 服务,它为每个用户会话实例化一次——指定为顶级用户组件的提供者。该服务会创建一个 observable,为该特定用户驱动一些后台处理。

这会泄漏内存吗?有没有办法知道实例化服务何时“完成”,以便我可以处理可观察的?我需要这样做吗?

这里是一些示例代码:

export class UserAppModel {

  constructor(
    private requestQueue: RequestQueue
  ) {
    Observable.interval(1000).subscribe(() => {
      this.requestQueue.enqueue(aRequest);
    });

}

换句话说,当用户会话正在进行时,我想每秒一次将特定请求排入队列。

UserAppModel 在顶级登录(会话)页面中“提供”为

@Component...
  providers: [UserAppModel]
)
export class SessionFrontPageComponent {
}

因此,如您所见,此流并未被可在 ngOnDestroy 上取消订阅的组件消耗。我想问这个问题的另一种方式是,UserAppModel 在该组件的providers 中列出时被实例化,然后在该组件“离开”时以某种方式销毁?即使是,我怎么知道,以便我可以处理可观察流?

【问题讨论】:

    标签: angular


    【解决方案1】:

    基本上有两种情况:

    1. 通过使用async 管道,您只能在模板中使用可观察数据。在这种情况下,Angular 会处理订阅,并在组件被销毁时取消订阅。这里无事可做。

    2. 您可以在代码中手动订阅,方法是在该 observable 上调用 subscribe 方法。在这种情况下,您应该在组件被销毁时手动取消订阅。

    要手动取消订阅,请使用 ngOnDestroy 生命周期挂钩:

    import {OnDestroy} from '@angular/core'
    @Component({...})
    class MyComponent implements OnDestory {
      // Component's code
      constructor(private myService: MyService) {
        this.subscription = myService.getData().subscribe(data => {...});
      }
    
    
      // Unsubscribe when the component is destroyed to avoid leaks.
      ngOnDestroy() {
        this.subscription.unsubscribe()
      }
    }
    

    在某些情况下,当 observables 自己触发 finish 信号时,您可以避免取消订阅它们,但由于它通常是异步的,并且您无法确定它在您的组件被销毁之前发生,因此最好手动处理。

    如果您对服务的 observable 是否结束感兴趣,可以使用带有三个参数的 do 运算符。

    @Injectable()
    export default class TestService {
    stream: Observable<number>;
    
    constructor() {
        this.stream = Observable.interval(1000)
        .do(
            data => console.log(data),
            error => console.log(error),
            () => console.log('FINISH') // On finish, all subscriptions will be disposed automatically
        );
    }
    

    .subscribe 也是如此。您可以使用组件中的第三个回调来记录流何时结束。

    更新:

    我想另一种提问方式是 UserAppModel 在提供者中列出时实例化 组件,然后当该组件“离开”时以某种方式销毁?

    您的服务仍将每秒执行这些操作。您可以在订阅中尝试console.log 的某些内容以查看这种情况。这真的就像在计划JS中设置超时一样。该函数将无限存在,并且可以访问服务实例,从而防止它被垃圾收集。

    作为旁注,我认为通过订阅 observables 来产生副作用是组件的角色,而不是服务的角色。这就是为什么他们首先有生命周期钩子。您可以考虑仅公开您的服务中的可观察对象,并在您的服务中管理订阅。这样您就不会遇到潜在的内存泄漏问题。

    export class UserAppModel {
      constructor(private requestQueue: RequestQueue) {}
      startFetchingData() {
          // As a bonus, if your requestQueue.enqueue is also an observable object,
          // you could just merge it together to even better control
          // the data (requests get cancelled when there's no active subscription)
          return Observable.interval(1000).mergeMap(() => {
              this.requestQueue.enqueue(aRequest);
          });
      }
    }
    
    class Component {
        ngOnInit() {
            this.subscription = this.userModel.startFetchingData().subscribe(data => {...})
        }
    
        ngOnDestroy() {
            this.subscription.unsubscribe();
        }
    }
    

    【讨论】:

    • 我已经为这个问题添加了更多信息,所以如果你能再看一下就好了。
    • 我已经在更新中添加了我的两分钱,但是 TL;DR 版本是:是的,它仍然会泄漏。
    【解决方案2】:

    如果每个会话只有一个(不确定如何定义会话,但这并不重要),我看不到任何可能的泄漏。 你应该确定只有一个, 和 OnDestroy 你可以完成 observable(关闭所有订阅者)。

    【讨论】:

    • 你指的是什么OnDestroy事件/
    • 好点。我认为最好的解决方案是在您的服务上添加 dispose 功能。并在销毁实例化它的根组件时调用它
    猜你喜欢
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多