これは主に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);
}
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()
を呼び出し、ConnectableObservable
がsource
をサブスクライブして、値の出力を開始します。今回はすでに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
これはあなたの質問を少し回避しますが、あなたはそれが役に立つかもしれません:
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*/
}
);
}