web-dev-qa-db-ja.com

RxJS-.subscribe()と.publish()。connect()

これは主にRxJのベストプラクティス/アプローチの質問です。私のPOCコードは機能しますが、RxJはまったく新しいのです。

質問は.subscribe().publish().connect()にまとめられます。どちらも同じように見えるためです。

私のangular2アプリには、ユーザーをログアウトする関数を呼び出すボタンがあります。これは、サーバー側のアクションを実行し、ユーザーをリダイレクトするURLを返すサービスの関数を呼び出します。リクエストを開始するために.subscribe()を呼び出して、オブザーバブルに値の生成を開始させます。私は「コールドvsホットオブザーバブル」に関する記事を読んでいましたが、もう1つのアプローチは、.publish().connect()ではなく.subscribe()を呼び出すことです。どちらのアプローチにもメリットはありますか?.

<a (click)="logout()">Logout</a>

ログアウト関数は次のようになります。

logout.component.ts

logout() { this.authService.logout(); }

そして、サービス(実際のログアウト)は次のようになります。

auth.service.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .subscribe();    // Option A - 

        return Observable.of(true);

    }

auth.service.alternative.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .publish()  // Option B - Make connectable observable
            .connect(); // Option B - Cause the connectable observable to subscribe and produce my value       

        return Observable.of(true);
    }
19
ClaytonK

subscribe().publish().connect()の違いは、ソースObservableをサブスクライブするときです。次の観察可能なことを考慮してください:

_let source = Observable.from([1, 2, 3])
_

このObservableは、サブスクライブすると、すべての値をオブザーバーに送信します。したがって、2つのオブザーバーがある場合、それらはすべての値を順番に受け取ります。

_source.subscribe(val => console.log('obs1', val));
source.subscribe(val => console.log('obs2', val));
_

これはコンソールに出力されます:

_obs1 1
obs1 2
obs1 3
obs2 1
obs2 2
obs2 3
_

一方、.publish()を呼び出すと ConnectableObservable が返されます。このObservableは、コンストラクターでソース(この例ではsource)をサブスクライブせず、参照のみを保持します。その後、複数のオブザーバーをサブスクライブすることができ、何も起こりません。最後に、connect()を呼び出し、ConnectableObservablesourceをサブスクライブして、値の出力を開始します。今回はすでに2つのオブザーバーがサブスクライブしているので、両方に値を1つずつ送信します。

_let connectable = source.publish();
connectable.subscribe(val => console.log('obs1', val));
connectable.subscribe(val => console.log('obs2', val));
connectable.connect();
_

コンソールに出力するもの:

_obs1 1
obs2 1
obs1 2
obs2 2
obs1 3
obs2 3
_

ライブデモをご覧ください: http://plnkr.co/edit/ySWocRr99m1WXwsOGfjS?p=preview

22
martin

これはあなたの質問を少し回避しますが、あなたはそれが役に立つかもしれません:

httpサービスを呼び出すのとは異なる監視可能なストリームを返さないでください。これを行うと、呼び出し元の関数で次のことができなくなります。

  • ストリームをキャンセルする
  • ストリームを変更する
  • 操作が成功したかどうかを判断する

代わりに私はやります:

auth.servive.ts

logout() : Observable<string>  {
       return this.http.get(...).map(this.extractData)          
            .catch(this.handleError);
}

これで、呼び出し元のコードは、結果のURLを使用して何でも実行できます

logout.component.ts

logout(){
    this.authService.logout().subscribe(
        url => window.location.href = url,
        err => {
            /*todo: handle if error was thrown by authService.handleError*/
        }
    );
}
4
BeetleJuice