Sergamers
@Sergamers
front-end

RxJS — Как правильно делать отписки на Subscriber объект?

public getAny(newParams: any): Subject<IRoomCard[]> {
    let params: any = this.generateQueryParams(newParams);

    // Поток
    const stream: Subject<IRoomCard[]> = new Subject();

    this.http.get(`/api/v1/p1`, {params: params})
    .subscribe(( res: IGetSearchId ) => {
      params.search_id = res.search_id;

      this.http.get(`/api/v1/p2`, {params: params})
      .subscribe(( res: IPrepeareRequest ) => {
        try{
          stream.next(res.search_result[0].rooms);
        } catch(err){
          stream.next([]);
        }
      });
    });

    return stream;
  }

// поправил реализацию
public getAny(newParams: any): Observable<IRoomCard[]> {
    let params: any = this.generateQueryParams(newParams);

    return this.http.get(`/api/v1/p1`, {params: params})
    .mergeMap(( res: IGetSearchId ) => {
      params.search_id = res.search_id;

      return this.http.get(`/api/v1/p2`, {params: params})
      .map(( res: IPrepeareRequest ) => {
        try{
              return res.search_result[0].rooms;
            } catch(err){
              return [];
            }
      });
    });
  }


export class TabNumberComponent implements OnInit, OnDestroy {
  constructor(
    private service: MyService,
  ) { }

  // Форма только инициализируется через сервис. Вносить изменения в сервис она не должна
  ngOnInit() {
    this.getListRooms();
  }

  ngOnDestroy() {
    // Отписываемся от подписок
    this.subscriptions.forEach(s => s.unsubscribe() );
  }

  // Получаем список комнат
  public getListRooms(): void {
    // Если уже идет отправка формы или форма не валидна
    if(this.isLoading || !this.form.valid){
      return;
    }

    this.isLoading = true;

    let SRooms = this.service.getAny(this.params).subscribe((rooms: IRoomCard[]) => {
      this.rooms = rooms;
    });

    this.subscriptions.push(SRooms);
  }
}


getListRooms() вызывается при ините, далее по кнопке, т.е. постоянно создается новый поток. Это влияет на производительность? (старые потоки никогда более не вызовутся, но по идее они должны съедать память раз они существуют). Их надо глушить оператором take чтоб освободить память? Нужна ли отписка холодных потоков при destroy если их не глушить?
  • Вопрос задан
  • 1957 просмотров
Пригласить эксперта
Ответы на вопрос 2
dasha_programmist
@dasha_programmist
ex Software Engineer at Reddit TS/React/GraphQL/Go
Стоит помнить разницу между Observable и Subject, соответственно subscribe у этих двух типов работает в части создания подписок по разному. Если закрывать весь стрим, то достаточно вызвать complete. Если нужно получить значение и отписаться то можно вызвать .first().subscribe(). Если создаются долгоживущие подписки, то их можно складывать в массив, а в дестрой вызывать subscriptions.forEach(i=>i.unsubscribe())

UPD: уточни бизнес-кейс, у меня подозрение что тут subject не нужен и можно обойтись new Observable((subs)=>{})
Ответ написан
loktionov129
@loktionov129
Backend .NET Developer
Вовсе не обязательно все подписки складывать в массив и затем в цикле от них отписываться в ngOnDestroy.
Можно обойтись таким способом:
import { Component, OnDestroy, OnInit } from '@angular/core';
import 'rxjs/add/operator/takeUntil';
import { Subject } from 'rxjs/Subject';

import { MyThingService } from '../my-thing.service';

@Component({
    selector: 'my-thing',
    templateUrl: './my-thing.component.html'
})
export class MyThingComponent implements OnDestroy, OnInit {
    private ngUnsubscribe: Subject<void> = new Subject<void>();

    constructor(
        private myThingService: MyThingService,
    ) { }

    ngOnInit() {
        this.myThingService.getThings()
            .takeUntil(this.ngUnsubscribe)
            .subscribe(things => console.log(things));

        this.myThingService.getOtherThings()
            .takeUntil(this.ngUnsubscribe)
            .subscribe(things => console.log(things));

    }

    ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы