web-dev-qa-db-ja.com

ホットおよびコールドオブザーバブル:「ホット」および「コールド」演算子はありますか?

私は次のSOの質問をレビューしました: ホットおよびコールドオブザーバブルとは何ですか?

要約する:

  • コールドオブザーバブルは、値を消費するオブザーバーがある場合に値を出力します。つまり、オブザーバーが受信する値のシーケンスは、サブスクリプションの時間とは無関係です。すべてのオブザーバーは同じ値のシーケンスを消費します。
  • ホットオブザーバブルは、サブスクリプションとは無関係に値を放出します。つまり、オブザーバーが受け取る値は、サブスクリプションの時間の関数です。

それでも、暑いのか寒いのかは依然として混乱の元だと感じています。だからここに私の質問があります:

  • すべてのrxオブザーバブルはデフォルトでコールドですか(サブジェクトを除く)?

    私は、イベントがホットなオブザーバブルの典型的なメタファーであることをよく読みますが、Rx.fromEvent(input, 'click')はコールドオブザーバブル(?)であることも読みます。

  • コールドオブザーバブルをホットオブザーバブルに変換するRx演算子(publishおよびshareを除く)はありますか?

    たとえば、Rx演算子withLatestFromとどのように機能しますか? _cold$_をどこかにサブスクライブされたコールドオブザーバブルにします。 sth$.withLatestFrom(cold$,...)はホットなオブザーバブルになりますか?

    または、sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)を実行し、_sth1_および_sth2_をサブスクライブすると、両方のsthに常に同じ値が表示されますか?

  • _Rx.fromEvent_はコールドオブザーバブルを作成すると思っていましたが、答えの1つで述べたように、そうではありません。しかし、私はまだこの動作に困惑しています: codepen.io/anon/pen/NqQMJR?editors=101 。異なるサブスクリプションは、同じオブザーバブルから異なる値を取得します。 clickイベントは共有されませんでしたか?

58
user3743222

数か月後に元の質問に戻ってきましたが、その間に得た知識を共有したいと思いました。説明のサポートとして次のコードを使用します( jsfiddle ):

var ta_count = document.getElementById('ta_count');
var ta_result = document.getElementById('ta_result');
var threshold = 3;

function emits ( who, who_ ) {return function ( x ) {
  who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n");
};}

var messages$ = Rx.Observable.create(function (observer){
  var count= 0;
  setInterval(function(){
    observer.onNext(++count);
  }, 1000)
})
.do(emits(ta_count, 'count'))
.map(function(count){return count < threshold})
.do(emits(ta_result, 'result'))

messages$.subscribe(function(){});

回答の1つで述べたように、オブザーバブルを定義すると、一連のコールバックとパラメーターの登録が行われます。データフローを開始する必要があり、それはsubscribe関数を介して行われます。 (説明のために簡略化された)詳細なフローは、その後見つけることができます。

Simplified flow diagram

オブザーバブルはデフォルトではコールドです。オブザーバブルをサブスクライブすると、アップストリームのサブスクリプションチェーンが発生します。最後のサブスクリプションは、ソースを処理し、そのデータをオブザーバーに送信する関数の実行につながります。

そのオブザーバーは次のオブザーバーに順番に送信し、データのダウンストリームフローをシンクオブザーバーに送ります。次の簡略図は、2人のサブスクライバが同じオブザーバブルをサブスクライブするときのサブスクリプションとデータフローを示しています。

Cold observable simplified flow diagram

ホットオブザーバブルは、サブジェクトを使用するか、multicast演算子(およびその派生物、下の注3を参照)を使用して作成できます。

内部のmulticast演算子は、サブジェクトを使用して、接続可能なオブザーバブルを返します。オペレーターへのすべてのサブスクリプションは、内部サブジェクトへのサブスクリプションになります。 connectが呼び出されると、内側のサブジェクトはアップストリームのobservableにサブスクライブし、データはダウンストリームに流れます。サブジェクトはサブスクライブされたオブザーバーのリストを内部で操作し、すべてのサブスクライブされたオブザーバーに着信データをマルチキャストします。

次の図は、状況をまとめたものです。

Hot observable simplified flow diagram

最後に、オブザーバーパターンとオペレーターの実装によって引き起こされるデータの流れを理解することが重要です。

たとえば、obsがホットの場合、hotOrCold = obs.op1はコールドですか、ホットですか?答えは何でも:

  • obs.op1の購読者がいない場合、op1を介してデータは流れません。ホットobsのサブスクライバーがいた場合、それはobs.op1がデータの一部を失う可能性があることを意味します
  • op1がマルチキャストライクな演算子ではないと仮定すると、hotOrColdに2回サブスクライブするとop1に2回サブスクライブし、obsからのすべての値はop1

ノート :

  1. この情報は、Rxjs v4で有効なはずです。バージョン5にはかなりの変更が加えられていますが、そのほとんどはまだそのままです。
  2. サブスクリプション解除、エラー、完了のフローは、質問の範囲外であるため表示されません。スケジューラも考慮されません。とりわけ、それらはデータフローのタイミングに影響しますが、その方向と内容には事前には影響しません。
  3. マルチキャストに使用されるサブジェクトのタイプに応じて、派生したマルチキャストオペレータが異なります。

Subject type | `Publish` Operator | `Share` operator ------------------ | --------------------------- | ----------------- Rx.Subject | Rx.Observable.publish | share Rx.BehaviorSubject | Rx.Observable.publishValue | shareValue Rx.AsyncSubject | Rx.Observable.publishLast | N/A Rx.ReplaySubject | Rx.Observable.replay | shareReplay

Update:参照してください 次の記事はこちらおよびそこ )レッシュ。

サブジェクトに関する詳細は、この他のSO質問: 異なるRxJSサブジェクトのセマンティクスは何ですか?

71
user3743222

あなたの要約とリンクされた質問は両方とも正しいです、私は用語があなたを混乱させるかもしれないと思います。ホットとコールドのオブザーバブルを、それぞれアクティブとパッシブのオブザーバブルとして考えることを提案します。

つまり、アクティブ(ホット)オブザーバブルは、誰かがサブスクライブしているかどうかに関係なく、アイテムを放出します。標準的な例では、ボタンクリックイベントは誰かが聞いているかどうかに関係なく発生します。この区別は重要です。たとえば、ボタンをクリックしてからボタンクリックを(この順序で)登録すると、既に発生したボタンクリックは表示されないためです。

パッシブ(コールド)オブザーバブルは、サブスクライバーが存在するまで待機してからアイテムを発行します。誰かがイベントを聞いているまでクリックできないボタンを想像してください。これにより、常にすべてのクリックイベントが表示されます。

すべてのRxオブザーバブルはデフォルトで「コールド」(またはパッシブ)ですか?いいえ、たとえばRx.fromEvent(input, 'click')はホット(またはアクティブ)オブザーバブルです。

また、Rx.fromEvent(input, 'click')はコールドオブザーバブル(?)

そうではありません。

コールドオブザーバブルをホットオブザーバブルに変えるRxオペレーターはいますか?

ホット(アクティブ)オブザーバブルをコールド(パッシブ)オブザーバブルに変える概念は次のとおりです。サブスクライブされていない間に発生するイベントを記録し、それらのアイテムを(さまざまな方法で)将来登場するサブスクライバーに提供する必要があります。これを行う1つの方法は、 Subject を使用することです。たとえば、ReplaySubjectを使用して、放出されたアイテムをバッファリングし、それらを将来のサブスクライバーにリプレイできます。

名前を付けた2つの演算子(publishおよびshare)は両方とも、サブジェクトを内部的に使用してその機能を提供します。

Rx演算子withLatestFromでどのように機能しますか? _cold$_をサブスクライブ済みのコールドオブザーバブルにします。 something$.withLatestFrom(cold$,...)はホットなオブザーバブルになりますか?

somethingがホットオブザーバブルの場合、はい。 somethingがコールドオブザーバブルの場合、いいえ。 somethingがボタンクリックイベントのストリームである場合、イベントの例に戻ります。

_var clickWith3 = Rx.fromEvent(input, 'click')
    .withLatest(Rx.Observable.from([1, 2, 3]);
_

または、foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)を実行し、fooおよびbarをサブスクライブすると、両方に常に同じ値が表示されますか?

常にではない。繰り返しますが、たとえばfoobarが異なるボタンをクリックした場合、異なる値が表示されます。同様に、それらが同じボタンであっても、組み合わせ関数(withLatestへの2番目の引数)が同じ入力に対して同じ結果を返さない場合、同じ値は表示されません(なぜなら、以下で説明するように、2回呼び出されます)。

_Rx.fromEvent_はコールドオブザーバブルを作成すると思っていましたが、答えの1つで述べたように、そうではありません。ただし、この動作にはまだ困惑しています: codepen.io/anon/pen/NqQMJR?editors=101 。異なるサブスクリプションは、同じオブザーバブルから異なる値を取得します。 clickイベントは共有されませんでしたか?

私は Enigmativityによるこの素晴らしい答え に私が同じ振る舞いについて持っていた質問を指摘します。その答えは、私ができるよりもずっとよく説明しますが、その要点は、ソース(クリックイベント)が「共有」されているということです。しかし、あなたの操作はそうではありません。クリックイベントだけでなく、その操作も共有する場合は、明示的に共有する必要があります。

8
Whymarrh

コードペンのvaluesは怠laです-何かがサブスクライブするまで何も起こりません。サブスクライブすると、それが実行されて接続されます。したがって、この例では、同じ変数にサブスクライブしていますが、2つの異なるストリームを作成しています。サブスクライブ呼び出しごとに1つ。

valuesは、clickが付加されたmapのストリームのジェネレーターと考えることができます。

そのマップの最後にある.share()は、暗黙的にサブスクライブしているため、予想される動作を作成します。

4
electrichead

それはあなたのすべての質問に対する答えではありません(それらすべてを知りたいです!)が、確かに、すべてのfromEvent Observableはホットです。 mousemoveのような「連続」イベントではないため、クリックは発生しないようですが、とにかくソースへのサブスクリプション(addEventListenerまたはon呼び出し)はObservableが作成されたときに1回だけ実行されます。暑いです。演算子 here および there のソースコードで確認できます。作成されたobservableは、イベント名やソースが何であれ、sharedです。

3
Eryk Napierała