我有一个Angular2服务,它为每个用户会话实例化一次 - 指定为顶级用户组件的提供者。该服务创建了一个observable,可以为该特定用户驱动一些后台处理。
这会泄漏内存吗?有没有办法知道实例化服务何时“完成”,以便我可以处置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
中列出时被实例化,然后在该组件“离开”时以某种方式被销毁?即使是这样,我怎么知道这样才能处理可观察的流?
答案 0 :(得分:5)
基本上有两种情况:
您只能在模板中使用async
管道来使用可观察数据。在这种情况下,Angular会处理订阅,并在销毁组件时取消订阅。这里无事可做。
您可以在代码中手动订阅,方法是在该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()
}
}
在某些情况下,当它们自己触发finish
信号时,你可以放弃不取消订阅,但由于它通常是异步的,你不能确定它在组件被销毁之前发生,它是最好手动处理它。
如果您对服务的可观察性是否结束感兴趣,可以使用带有三个参数的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中设置超时一样。该函数将无限生存,并且可以访问服务实例,防止它被垃圾回收。
作为旁注,我认为通过订阅observable来创建副作用是组件的角色,而不是服务。这就是他们首先拥有生命周期钩子的原因。您可以考虑仅从服务中公开observable,并在您的服务中管理订阅。这样你就不会遇到潜在的内存泄漏问题。
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();
}
}
答案 1 :(得分:3)
如果每个会话中只有一个(不确定如何定义会话但不重要)我没有看到任何可能的泄漏。 你应该确定只有一个, 和OnDestroy你可以完成observable(关闭所有订阅者)。