Angular2: отписаться от http, наблюдаемого в Сервисе

Какова лучшая практика, чтобы отписаться в службе Angular2 от подписки http?

В настоящее время я делаю это, но я не уверен, будет ли это лучшим способом.

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";

import { Subject } from "rxjs/Subject";
import { ISubscription } from "rxjs/Subscription";

@Injectable()
export class SearchService {
    private _searchSource = new Subject<any>();

    public search$ = this._searchSource.asObservable();

    constructor(private _http: Http) {}

    public search(value: string) {
        let sub: ISubscription = this._http.get("/api/search?value=" + value)
            .map(response => <any>response.json())
            .do(data => this._searchSource.next(data))
            .finally(() => sub.unsubscribe()).subscribe();
    }

}

4 ответа

Решение

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

Причина, по которой вам нужно отписаться от заметки, состоит в том, чтобы избежать утечек памяти. Когда вы получаете утечки памяти? Если что-то было собрано мусором, в то время как оно все еще было подписано на наблюдаемый, слушатель событий, сокет,...

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

Вывод: отписываться в сервисе бессмысленно, так как нет утечек памяти.

Я не согласен с ответом KwintenP. Да, в случае наблюдаемого вызова HttpClient нет необходимости отказываться от подписки, поскольку Владимир правильно упомянул, однако в других наблюдаемых вам определенно может потребоваться отказаться от подписки в службе.

Давайте посмотрим на простой пример: предположим, что у нас есть хранилище, которое отправляет наблюдаемые, и в хранилище у нас есть clicker наблюдаемый огонь true всякий раз, когда щелкают правой кнопкой мыши (по какой-то странной причине) И предположим, что у нас есть MyWeirdService которые делают следующее:

class MyWeirdService {
  doSomethingUnthinkableManyTimes() {
    this.store.select('clicker').subscribe(() => {
      console.log("Hey what do you know, I'm leaking");
    });
  }
}

this.store.select('clicker') возвращает наблюдаемое, что мы регистрируем для него новый обработчик при каждом вызове doSomethingUnthinkableManyTimes без очистки, что приведет к утечке памяти, которая будет оставаться, пока существует служба (во многих случаях время жизни приложения)

В итоге вам не нужно отказываться от подписки в приведенном выше случае с Http, как Владимир хорошо объяснил это, но в других случаях вам это может понадобиться.

-------------- Издание ------------

Чтобы решить эту проблему в моем примере, просто добавьте take(1) и он будет автоматически отказываться от подписки после запуска каждого потока:

class MyWeirdService {
  doSomethingUnthinkableManyTimes() {
    this.store.select('clicker')
     .pipe(take(1))
     .subscribe(() => {
      console.log("What a relief, I'm not leaking anymore");
     });
  }
}

Вам не нужно отписываться от заметок, созданных Http или же HttpClient потому что оно конечно наблюдаемо (значение будет испущено только один раз и complete будет называться).

Тем не менее, вы можете отписаться от заметки, созданной HttpClient отменить запрос. Это означает, что вас больше не интересуют данные, возвращаемые запросом.

Вы можете сделать это:

      You need to understand that the service file should be used to just define the http methods and not subscribe there itself. 
Create the method in the service file, use Dependency injection to inject that service in the component and then use ngOnDesteoy to kill the subscription 

****** this is in your component.ts file *******
// introduce a new subject variable to destroy the subscription
destroy$: Subject<any> = new Subject();

constructor(private serviceName: yoirService){} // Dependency injection 

// wherever you want to unsubsribe an observable or a subscription
this.serviceName.observableName.pipe(takeUntil(this.destroy$)).subscribe(
    // required code 
);

//  use ngOnDestroy() to kill it
ngOnDestroy() {
   this.destroy$.next();
   this.destroy$.complete();
}

This way you'll destroy the service once the component is destroyed. 

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