概要
Observableを学ぶ上でCold ObservableとHot Observableの違いを理解していた方が良いと聞いたので調べてみました。
環境
- rxjs 5.1.0
ざっくり表
Cold Observable | Hot Observable | |
---|---|---|
イメージ | オンデマンド再生のような、選んだら再生。 再生するシーンは開始タイミングに依るので、人によってそれぞれ |
テレビのような垂れ流し。 再生するシーンは皆同じ。 |
データの開始タイミング | subscribe()されたら | connect()されたら |
データを流すStreamの数 | subscribeしてる数 | 1つ。いくつsubscribeしても同じStreamを見る |
データを受け取るStreamの数 | subscribeしてる数 | subscribeしてる数。 送信してるStreamは1つでも、unsubscribeは受信してる個々で行う必要がある |
データの開始タイミング
Cold Observable
先程のsubscribeされたらデータ送信が開始するを確かめるために以下のコードを作ってみました。
const obs = Rx.Observable.create( observer => { const now = Date.now(); observer.next(now); } ); obs.subscribe( v => { console.log("1st: " + v); } ); obs.subscribe( v => { console.log("2nd: " + v); } );
結果
"1st: 1488076511239" "2nd: 1488076511240"
Cold Observableはsubscribeする度に別のStreamとして扱われるので、subscribeが複数ある=それぞれでデータ送信を開始し、時間もズレていることがわかります。
Hot Observable
こちらはconnect()されたらデータ送信が開始するので確かめます。
const obs = Rx.Observable.create( observer => { const now = Date.now(); observer.next(now); } ).publish(); // publish すればHot Observableになる obs.subscribe( v => { console.log("1st: " + v); } ); obs.subscribe( v => { console.log("2nd: " + v); } ); obs.connect();
ポイントはsubscribe
のあとでconnect
を実行しています。
これはconnectがデータの開始タイミングなので、subscribeの前にデータを流してしまうと受け取れなくなるからです。
結果
"1st: 1488077002839" "2nd: 1488077002839"
ちゃんと受け取れてますね。またHot Observableは同じStreamを見ているので、日付も同じ値が返ってきます。
connectを先に書いたら?
const obs = Rx.Observable.create( observer => { const now = Date.now(); observer.next(now); } ).publish(); obs.connect(); // 先に書く obs.subscribe( v => { console.log("1st: " + v); } ); obs.subscribe( v => { console.log("2nd: " + v); } );
結果
先程も説明したように、connect後=データの送信後にsubscribeすることになるので、返ってこなくなります。
Hot ObservableのrefCount
先程の話でHot Observableはconnectを実行して初めてデータ送信が開始されることが分かりました。
ただこれだとそのStreamがいつ開始されているのかを把握していなくてはいけません。
そういった依存を解決できるのがrefCount
です。
const obs = Rx.Observable .interval(1000) .take(5) .publish() .refCount(); setTimeout( () => { obs.subscribe( v => { console.log("1st: " + v); } ); }, 1000); setTimeout( () => { obs.subscribe( v => { console.log("2st: " + v); } ); }, 3100);
intervalでStreamにデータを送り、1秒後と3秒後にsubscribeを開始しています。
refCount
を使うとCold Observableのように、最初のsubscribeでデータ送信を開始してくれます。
結果
"1st: 0" "1st: 1" "1st: 2" "2st: 2" "1st: 3" "2st: 3" "1st: 4" "2st: 4"
また結果からわかるように、Cold Observableと異なり、各subscribeが見ているStreamは1つであるというHot Observableの性質はちゃんと保持しています。
ちなみに.publish().refCount()
はよく使われるので、.share()
でまとめて1つで書けたりします。
例えばどこで使われているか
Cold Observable
Angular2のHttpModule
はCold Observableです。
なのでsubscribeするまではhttpリクエストを実行しませんし、もし同じStreamに対して2回subscribeすればhttpリクエストも2回実行されます。
Hot Observable
mousemove
イベントやticker
で使われます。
まとめ
ColdかHotなのかを理解して使い分けが出来ると、シーンに応じてより適切なObservableの扱い方が出来ると思います。