У меня есть приложение в angular 4, и я собрал почти все компоненты таким образом:

 export class AreaProdottiComponent implements OnInit,OnDestroy {

    subscription: ISubscription;


    constructor(private someservice:Service){
        this.subscription = someserviceObservable.subscribe(
                res=>{
                    console.log('everything ok')
                }
        )
    }

    ngOnInit(){
        this.someservice.fn()
    }

    ngOnDestroy(){
        this.subscription.unsubscribe()
    }
}

Эти компоненты взаимодействуют с сервисами, построенными почти таким образом:

export class Service(){        
    someservicesubj=Subject<any>();
    someserviceObservable=someservicesubj.asObservable();

    fn(){
        doCall.subscribe(
                res=>{
                    this.someservicesubj.next();
                }
        )
    }

    doCall()Observable<any>{
        //some http call is here
    }
}

Поэтому, когда создаются такие компоненты, они вызывают автоматический HTTP-метод из служб, и все вроде работает, но если я перехожу к приложению и возвращаюсь к тому же компоненту во второй раз, количество вызовов, которые совершаются, как только компонент создан дублирован, метод fn вызывается 2 раза. Это поведение усиливается каждый раз, когда я уничтожаю и воссоздаю компонент.

Примере:

Открывая компонент в консоли, я читаю «все в порядке», выхожу и возвращаюсь, я прочитаю «все в порядке» 3 раза, старый плюс 2 других.

Я думаю, что упускаю что-то в стратегии навигации или в построении сервиса, но я действительно не могу найти решение.

Обновить

Я пробовал, как предложил @trichetriche, но это все еще не работает. я использовал ISubscription вместо этого, это возможная проблема?

Обновить

@trichetriche был прав, но у меня была услуга, вызванная другим подписчиком, поэтому я пропустил тот факт, что это была первая услуга, подписка на которую была отменена.

-1
mautrok 13 Мар 2018 в 14:37

2 ответа

Лучший ответ

Это потому, что подписки нужно закрывать, когда вы их открываете. И вы их не закрываете.

Однако я не буду комментировать неудачу создания тем для HTTP-вызовов.

export class AreaProdottiComponent implements OnInit, OnDestroy {

  subscription: Subscription;

  constructor(private someservice:Service){
    this.subscription = someserviceObservable.subscribe(res => console.log('everything ok'));
  }

  ngOnInit(){
    this.someservice.fn()
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Если вы хотите автоматически отказаться от подписки, вы можете использовать для этого декоратор.

export const randomString = () => Math.random().toString(36).slice(-8);

export function AutoUnsubscribe(blacklist = []) {
  return function (constructor) {
    const original = constructor.prototype.ngOnDestroy;
    constructor.prototype.ngOnDestroy = function () {
      // tslint:disable-next-line:forin
      for (const prop in this) {
        const property = this[prop];
        if (!blacklist.includes(prop)) {
          if (property && (typeof property.unsubscribe === 'function')) {
            property.unsubscribe();
            // console.log(prop + ' unsubscribed');
          }
        }
      }
      if (original && typeof original === 'function') { original.apply(this, arguments); }
    };
  };
}

Теперь ваш компонент будет выглядеть так

@AutoUnsubscribe()
export class AreaProdottiComponent implements OnInit, OnDestroy {

  subscription: Subscription;

  constructor(private someservice:Service){
    this[randomString()] = someserviceObservable.subscribe(res => console.log('everything ok'));
  }

  ngOnInit(){
    this.someservice.fn()
  }
}
1
user4676340user4676340 13 Мар 2018 в 11:42

Причина в том, что вы никогда не отказываетесь от подписки, которую создаете в конструкторе компонентов. Каждый раз, когда создается экземпляр компонента, открывается новая подписка, и поэтому журналы увеличиваются на единицу при каждом переходе к этому компоненту.

Если вы хотите предотвратить такое поведение, вам следует сохранить подписку и закрыть ее с помощью метода ngOnDestroy:

export class AreaProdottiComponent implements OnInit, OnDestroy {
    private subscription: Subscription;

    constructor(private someservice:Service){
        this.subscription = someserviceObservable.subscribe(
                res=>{
                    console.log('everything ok')
                }
        )
    }

    ngOnInit(){
        this.someservice.fn()
    }

    public ngOnDestroy(): void {
        if (this.subscription) this.subscription.unsubscribe();
    }
}
0
Markai 13 Мар 2018 в 11:46