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();
    }

}

person NCC-2909-M    schedule 29.11.2016    source источник
comment
Кажется избыточным и бессмысленным отписываться, когда наблюдаемое завершается.   -  person Günter Zöchbauer    schedule 29.11.2016
comment
@günter-zöchbauer Ну, это был не мой вопрос, если это имеет смысл, мой вопрос был: как лучше всего. Так?   -  person NCC-2909-M    schedule 30.11.2016
comment
Я не думаю, что есть лучшие практики для вещей, которые не имеют смысла :D Возможно, просто - не делайте этого.   -  person Günter Zöchbauer    schedule 30.11.2016
comment
И что мне не следует делать? @günter-zöchbauer Может быть, объяснение было бы отличным вместо бесполезных комментариев   -  person NCC-2909-M    schedule 30.11.2016


Ответы (4)


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

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

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

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

person KwintenP    schedule 30.11.2016
comment
Спасибо за ответ @kwintenp. Но, как вы видите выше, каждый вызов метода поиска будет создавать новую наблюдаемую, на которую я должен подписаться, чтобы получить данные. Разве я не должен был отказаться от подписки, чтобы избежать утечек памяти? - person NCC-2909-M; 30.11.2016
comment
Это нормально. Каждая возвращенная подписка очистится. Служба HTTP убирает за собой. Когда получен результат XHR, вызывается полный метод подписки, который отменяет подписку. Однако может возникнуть случай вызова метода отмены подписки для возвращаемого Observable службы http. Если бы мы когда-нибудь захотели отменить текущий HTTP-запрос, мы бы вызвали отписку. Это вызывает прерывание под обложками, чтобы завершить очистку. - person Thibs; 30.11.2016
comment
сервис будет существовать на протяжении всего срока службы вашего приложения, это неправда. Я могу предоставить услугу только на время жизни компонента, так что он будет уничтожен, когда компонент будет уничтожен... - person Markus Ende; 09.06.2017
comment
Вывод: Отписываться в сервисе как бы бессмысленно, так как исключена утечка памяти. Я думаю, что правильнее сказать, что отмена подписки на наблюдаемые, созданные службой http angular, не требуется. Может возникнуть ситуация, когда служба, совместно используемая двумя компонентами, ссылается на некоторый объект внутри подписки. Если эта общая служба получает сборку мусора (см. комментарий @MarkusE. выше), вы можете столкнуться с утечкой памяти. - person instantaphex; 18.07.2017
comment
Если некоторые наблюдаемые объекты совместно используются компонентами, которые доступны, например, через службу Angular, они могут быть подписаны несколько раз, пока компонент инициализируется. Поэтому мы должны всегда отписываться от них. - person Mouneer; 07.08.2018
comment
Нас вообще беспокоит использование памяти? - person Ben Racicot; 30.04.2019
comment
Я знаю, что это старая ветка, но мне захотелось добавить ее, потому что я пришел сюда в поисках информации о том, как отписаться от наблюдаемых внутри службы, когда они не являются синглтонами (специально). Я придерживаюсь формата возврата наблюдаемого как части интерфейса ответа, чтобы вызывающий компонент мог отказаться от подписки на него, когда захочет. Надеюсь это поможет. - person automaticAllDramatic; 20.04.2020

Я не согласен с ответом 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");
     });
  }
}
person Kfir Erez    schedule 13.08.2019

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

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

person Vladimir Prudnikov    schedule 30.04.2019

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

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. 

person Srikar Phani Kumar Marti    schedule 26.02.2021