web-dev-qa-db-ja.com

Angular2:サービスで監視可能なhttpからサブスクライブ解除

HttpサブスクリプションからAngular2サービス内でサブスクリプションを解除するためのベストプラクティスは何ですか?

現在これを行っていますが、これが最善の方法かどうかはわかりません。

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

}
30
NCC-2909-M

Angularのサービスはシングルトンです。これは、サービスがアプリケーションの寿命全体にわたって存在することを意味します。

オブザーバブルからサブスクライブを解除する必要がある理由は、メモリリークを回避するためです。メモリリークはいつ発生しますか?監視可能なイベントリスナー、ソケットなどにサブスクライブされている間に何かがガベージコレクションされた場合...

Angularサービスは決して破壊されないので、アプリケーション全体が破壊されない限り、サブスクライブを解除する本当の理由はありません。 。

結論:メモリリークの可能性がないため、サービスでのサブスクライブ解除は無意味です。

71
KwintenP

HttpまたはHttpClientによって作成されたobservableからサブスクライブを解除する必要はありません。これは有限のオブザーバブルです(値は一度だけ発行され、completeが呼び出されます)。

ただし、HttpClientによって作成されたオブザーバブルからリクエストをキャンセルに登録解除できます。これは、リクエストによって返されるデータに関心がなくなったことを意味します。

2

KwintenP answerに同意しません。はい。HttpClient呼び出しでオブザーバブルの場合、 Vladimir として正しくサブスクライブ解除する必要はありませんが、他のオブザーバブルでは、サービスでサブスクライブ解除する必要があります。

簡単な例を見てみましょう:オブザーバブルを送信するストアがあり、ストア内で右マウスがクリックされるたびに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を呼び出すたびに新しいハンドラーを登録することを示すオブザーバブルを返します。クリーニングせずに、サービスが存在する限りメモリリークが発生します(多くの場合、アプリケーションの有効期間)

Vladimir で説明されているように、上記のHttpの場合は購読を解除する必要はありませんが、他の場合は必要になるかもしれません。

1
Kfir Erez