Утечка памяти Angular и подписка не работает должным образом

Я пробую Ionic и хотел сделать конвертер валют на практике. Приложение извлекает некоторые данные из API Rest, а затем во внешнем интерфейсе используется для расчета обменного курса определенной суммы денег. Я хочу, чтобы он работал так же, как работает preev.com.

У меня есть служба, которая получает данные из API Rest и принимает два параметра, которые являются валютами для конвертации. Затем служба отправляет запрос на получение в нужную конечную точку в зависимости от параметров / валют.

На моей странице у меня есть функция, которая отправляет параметры / валюты службе, а затем подписывается на нее.

В этой части у меня две проблемы:

  1. Во-первых, потому что это наблюдаемое, оно слишком часто обновляется. Я попытался решить эту проблему, отправляя интервальный запрос на сервер каждые 60 секунд, но это не сработало, а другой способ, которым я пытался решить эту проблему, заключался в попытке получить значение один раз из компонента перед подпиской с помощью метода first().

  2. Когда я переключаюсь между валютами в моем выбранном компоненте, targetAmount мигает между текущей обменной стоимостью и прошлой обменной стоимостью. Например, валюты по умолчанию для обмена в моем приложении - BTC / CLP, но когда я выбираю BTC / COP, он мигает двумя курсами обмена в течение нескольких секунд, пока не покажет текущий обменный курс, который я собираюсь использовать. Наконец, когда я переключаюсь между валютами, не дожидаясь отображения только текущего обмена, происходит сбой.

Вот мой код:

Страница:

export class Page {

  baseCurrency = 'BTC';
  targetCurrency = 'CLP';
  baseAmount = 1;
  exchangeRate: number;
  subscription;

  constructor(public navCtrl: NavController,
    private exchangeService: ExchangeService) {

  }

  supportedCurrencies = ['BTC', 'ETH', 'BCH'];
  supportedCurrencies2 = ['CLP', 'COP', 'PEN'];

  get targetAmount() {
    this.subscription = this.exchangeService.getBudaFiat(this.baseCurrency, this.targetCurrency)
    .first()
    .subscribe(
      val => {
        this.exchangeRate = val.ticker.last_price[0];
      }
    )
    return this.baseAmount * this.exchangeRate;
  }

  ionViewWillLeave() {
    this.subscription.unsubscribe();
    console.info("SALIO");
  }

}

HTML:

<ion-content>
  <ion-list>
    <input type = "number" [(ngModel)] = "baseAmount"
      [class.error] = "isInvalid(baseAmount)">
    <currency-select [(selected)] = "baseCurrency"></currency-select>
    = <strong>{{targetAmount}}</strong>
    <currency-select2 [(selected)] = "targetCurrency"></currency-select2>
    <p *ngIf = "isInvalid(baseAmount)">Please enter a valid amount</p>
  </ion-list>
</ion-content>

Услуга:

getBudaFiat(baseCurrency: string, targetCurrency: string) {
    return Observable.interval(60000)
    .startWith(0)
    .switchMap(() => {
      return this.http.get(`https://wt-e2369b36b992e69ccc8f05d9b48dd8e2-0.sandbox.auth0-extend.com/cryptoalarma/${baseCurrency}${targetCurrency}`)
      .map((response: Response) => response);
    });
  }

Код также доступен на Stackblitz, и вы можете проверить проблему на вкладке «Контакт»:

Ссылка на приложение Stackblitz

Спасибо за вашу помощь!

Обновлено:

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

Где эта утечка памяти указана в заголовке ??

Antoniossss 07.05.2018 20:48

@Antoniossss, извини, я исправил.

claudiomatiasrg 07.05.2018 20:55
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
61
2

Ответы 2

Вам необходимо правильно импортировать подписку:

import {Subscription} from 'rxjs/Subscription';

а затем введите переменную подписки:

subscription: Subscription;

и наконец

this.subscription.unsubscribe();

Последняя часть самая важная.

Robin Dijkhof 07.05.2018 21:18

Если вы попытаетесь отказаться от подписки, для которой не введена подписка, подписка не будет отменена. Это также должно дать вам ошибку линтинга.

Sandra Willford 07.05.2018 21:21

Привет, Сандра, спасибо за помощь, но это не работает. Он отписывается, когда я покидаю страницу, но у меня все еще есть основные проблемы. Если я переключаюсь между валютами, он начинает использовать много памяти и мигает обменные курсы. Вы можете проверить это здесь: stackblitz.com/edit/ionic-yljfbt?file=pages%2Fabout%2Fabout.‌ ts Ваше решение реализовано на вкладке «О программе».

claudiomatiasrg 07.05.2018 21:56

Обычно это происходит из-за того, что вы отказались от подписки, но ваша тема все еще отправляет ...

Sandra Willford 08.05.2018 12:01

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

  1. создайте переменную с именем alive со значением по умолчанию true
  2. Используйте .takeWhile(() => this.alive) перед subscribe
  3. реализовать OnDestroy
  4. установить для alive значение false на ngOnDestroy

тогда автоматически он отменит подписку, наблюдаемую, когда ваш компонент будет уничтожен

export class MyComponent implements OnDestroy, OnInit {

  public user: User;
  private alive: boolean = true;

  public ngOnInit() {
    this.userService.authenticate(email, password)
      .takeWhile(() => this.alive)
      .subscribe(user => {
        this.user = user;
      });

    this.otherService.getdata()
      .takeWhile(() => this.alive)
      .subscribe(data => {
      });

  }

  public ngOnDestroy() {
    this.alive = false;
  }

}

Вы можете прочитать больше в здесь

Привет, Реза Рахмати, спасибо за помощь, но это не работает. Он по-прежнему использует много памяти, а также отображает курсы обмена валют. Вы можете проверить это здесь: stackblitz.com/edit/… Ваше решение реализовано на вкладке «Контакты».

claudiomatiasrg 07.05.2018 21:59

@ ClaudioRamírezGuichard, вы не реализовали OnDestroy и ngOnDestroy, чтобы установить alive на false

Reza 07.05.2018 22:01

Сделал, просто после того, как не вышло, попробовал с ionViewWillLeave(). В любом случае, в той ссылке, которую вы мне дали, она все еще мигает среди обменных курсов, когда вы переключаете валюты, в которые нужно конвертировать. Кстати, я только что понял, что http тоже не работает и начинает показывать много ошибок в консоли. Когда это происходит, утечки памяти увеличиваются.

claudiomatiasrg 07.05.2018 22:10

@ ClaudioRamírezGuichard Проблема с вашим кодом заключается в том, что вы подписываетесь на get targetAmount, что означает, что каждый раз, когда вызывается свойство get, вы подписываетесь снова, вместо этого лучше иметь обработчик событий для изменения валюты, вызывать свой api с помощью first () или take (1) и сохраните общую сумму в переменной.

Reza 08.05.2018 18:49

Другие вопросы по теме