【问题标题】:Angular 8 memory leak, adds more and more subscriptionsAngular 8 内存泄漏,添加越来越多的订阅
【发布时间】:2020-03-05 12:39:31
【问题描述】:

问题:

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

代码

servers.component.html

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

服务器备份.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);

}

最后在我的 data-storage-service.ts 上

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

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

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

【问题讨论】:

  • 没有变量我很累。我也试过这个: if (!this.serverPerfSub) { //get the data } 这没用。问题是何时以及如何清理 DataStorageSerivce 上的订阅?因为它始终存在并且不断收到越来越多的对我的 api 的调用。订阅列表不在 dataStorageService 上

标签: javascript angular angular8


【解决方案1】:

Javascript

您需要清除您的setInterval。

interval: number;

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

ngOnDestroy() {
  clearInterval(this.interval);
}

RxJS

这可以使用 javascript 完成,但我建议使用 RxJS interval,因为您已经在处理 observables。

既然你想立即调用它,你最好使用 RxJS timer。

// 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 请求之后不久。

【讨论】:

  • 谢谢,我应用了这些更改。我得到的原始错误“查询处理器无法启动并行查询执行所需的线程资源。”仍然存在,现在它在几次调用后每 5 秒停止调用该方法..
  • 你能在 stackblitz 中重新创建吗?
  • 我无法访问我的工作。但是,我确实注意到我没有提到的一件事是,当我记录我的 dataAccessService 时间时,我看到它每 5 秒被调用两次(直到它失败然后停止尝试) Thu Mar 05 2020 15:13:06 GMT+0200 data-storage.service.ts:100 Thu Mar 05 2020 15:13:06 GMT+0200 data-storage.service.ts:100
  • 无论如何,您的代码会因错误而停止,并且由于我仍然遇到相同的错误,因此它会一直运行直到遇到此错误并停止刷新我的数据。在以前的方法上它一直在尝试。有时成功,有时失败。
  • 如果您无法访问 stackblitz,那么您可以访问其他任何现场演示站点吗?可能有些地方不太对劲,但没有共享演示就无法知道。
猜你喜欢
  • 1970-01-01
  • 2020-09-13
  • 2021-12-13
  • 1970-01-01
  • 2012-09-15
  • 2016-01-09
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多