Angular 8 утечка памяти, добавляет все больше и больше подписок - PullRequest
1 голос
/ 05 марта 2020

Проблема:

Мое приложение работает нормально на первом загружаемом компоненте, и когда я нажимаю, чтобы переключиться на другой компонент, оно создает другую подписку на My DAL.

Код

servers.component. html <- компонент по умолчанию </p>

<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 Я хочу обновлять sh данные из БД каждые 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, но как мне это очистить?

1 Ответ

3 голосов
/ 05 марта 2020

Javascript

Вам необходимо очистить setInterval.

interval: number;

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

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

Rx JS

Это можно сделать с помощью javascript, но я бы рекомендовал использовать Rx JS interval, поскольку вы уже имеете дело с наблюдаемыми.

И так как вы хотите немедленно вызвать его, вам лучше использовать Rx JS 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.

data-storage-service.ts

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

component.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-запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...