Angular 8内存泄漏,增加了越来越多的订阅



问题:

我的应用程序在我加载的第一个组件上运行良好,当我点击切换到另一个组件时,它会在我的DAL上创建另一个订阅。

代码

servers.component.html<-默认组件

<div class="row">
<div class="col-md-12">
<app-server-list></app-server-list>
</div>
<router-outlet></router-outlet>
</div>

server-backup.component.html

<div class="row">
<div class="col-md-12">
<app-server-list ></app-server-list>
</div>
</div>

在server-list.component.ts中,我想每5秒刷新一次数据库中的数据,所以我这样做:

this.dataStorageService.getServerPerformanceInfo()
this.interval = setInterval(() =>
{
this.dataStorageService.getServerPerformanceInfo()
} , 5000)

当我在服务器和服务器备份之间切换时,我取消订阅:

ngOnDestroy()
{
this.subscriptions.forEach(subscription => {
subscription.unsubscribe();  
});
clearInterval(this.interval);

}

最后在我的数据存储服务上。ts

getServerPerformanceInfo()
{
this.serverPerfSub = this.http.get<ServerPerformance[]>(DEV + '/getServerPerformance').subscribe
(
(data) => {
this.serversService.setPerformanceInfo(data);
}
)
}

当我在组件之间切换时,服务器列表组件被销毁、创建,但dataStorageService调用变得越来越频繁,直到我的API方法开始失败。

当然,这与dataStorageService上的订阅有关,但我该如何清理呢?

Javascript

您需要清除setInterval

interval: number;
ngOnInit() {
this.dataStorageService.getServerPerformanceInfo()
this.interval = setInterval(() => {
this.dataStorageService.getServerPerformanceInfo();
} , 5000);
}
ngOnDestroy() {
clearInterval(this.interval);
}

RxJS

这可以用javascript来完成,但我建议使用RxJSinterval,因为您已经在处理可观察性了。

既然您想立即调用它,那么最好使用RxJStimer

// import { timer, Subject } from 'rxjs';
// import { takeUntil, catchError } from 'rxjs/operators';
private destroyed$ = new Subject();
ngOnInit() {
// start the timer and initiate the observable immediately.
// then emit a value every 5 seconds
timer(0, 5000).pipe(
// unsubscribe on ngOnDestroy
takeUntil(this.destroyed$)
).subscribe(() => {
// TODO: catch errors in data storage service
this.dataStorageService.getServerPerformanceInfo();
});
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}

将订阅从您的服务中移出

不过,我建议将您的订阅从您的服务中删除。您仍然可以在tap运算符中执行操作。您可以在组件中使用switchMap将服务调用链接到timer

数据存储服务.ts

getServerPerformanceInfo(): Observable<any> {
const url = DEV + '/getServerPerformance';
return this.http.get<ServerPerformance[]>(url).pipe(
tap((data) => this.serversService.setPerformanceInfo(data))    
);
}

组件.ts

ngOnInit() {
timer(0, 5000).pipe(
takeUntil(this.destroyed$),
switchMap(() => this.dataStorageService.getServerPerformanceInfo()),
catchError(error => of('An error has occured'))
).subscribe(() => {
// TODO: Something?
});
}

如果要捕获错误,可以使用catchError在管道中捕获它们。我建议尽可能靠近源代码捕获它们——最好是在http请求之后不久。

最新更新