RxJs 5 share()
演算子がどのように機能するかは100%明確ではありません。ここで 最新のドキュメント を参照してください。質問のJsbin ここ 。
一連の0〜2のオブザーバブルを作成すると、各値は1秒ごとに区切られます。
_var source = Rx.Observable.interval(1000)
.take(5)
.do(function (x) {
console.log('some side effect');
});
_
そして、このオブザーバブルの2つのサブスクライバーを作成した場合:
_source.subscribe((n) => console.log("subscriptor 1 = " + n));
source.subscribe((n) => console.log("subscriptor 2 = " + n));
_
コンソールでこれを取得します:
_"some side effect ..."
"subscriptor 1 = 0"
"some side effect ..."
"subscriptor 2 = 0"
"some side effect ..."
"subscriptor 1 = 1"
"some side effect ..."
"subscriptor 2 = 1"
"some side effect ..."
"subscriptor 1 = 2"
"some side effect ..."
"subscriptor 2 = 2"
_
各サブスクリプションは同じObservableにサブスクライブすると思っていましたが、そうではないようです!サブスクライブする行為のように、完全に独立したObservableが作成されます!
しかし、share()
演算子がソースobservableに追加された場合:
_var source = Rx.Observable.interval(1000)
.take(3)
.do(function (x) {
console.log('some side effect ...');
})
.share();
_
次に、これを取得します。
_"some side effect ..."
"subscriptor 1 = 0"
"subscriptor 2 = 0"
"some side effect ..."
"subscriptor 1 = 1"
"subscriptor 2 = 1"
"some side effect ..."
"subscriptor 1 = 2"
"subscriptor 2 = 2"
_
これは、share()
なしで期待するものです。
ここで何が起こっていますか、share()
operatorはどのように機能しますか?各サブスクリプションは、新しいオブザーバブルチェーンを作成しますか?
ドキュメントリンクがRxJS v4のように見える一方で、RxJS v5を使用していることに注意してください。具体的なことは覚えていませんが、share
演算子は、特に完了と再購読に関してはいくつかの変更を経たと思いますが、私のWordを受け入れません。
質問に戻って、あなたの研究で示したように、あなたの期待は図書館の設計に対応していません。オブザーバブルは、データフローを遅延的にインスタンス化し、サブスクライバーがサブスクライブすると、具体的にデータフローを開始します。 2番目のサブスクライバーが同じオブザーバブルをサブスクライブすると、別の新しいデータフローが最初のサブスクライバーであるかのように開始されます(したがって、各サブスクリプションは、前述のようにオブザーバブルの新しいチェーンを作成します)。これは、RxJSの用語ではコールドオブザーバブルと呼ばれるものであり、RxJSオブザーバブルのデフォルトの動作です。データが到着した時点で持っているサブスクライバにデータを送信するオブザーバブルが必要な場合、これはホットオブザーバブルと呼ばれます。ホットオブザーバブルを取得する1つの方法は、share
演算子を使用することです。
ここで、図解されたサブスクリプションとデータフローを見つけることができます: ホットおよびコールドオブザーバブル:「ホット」および「コールド」演算子はありますか? (これはRxJS v4で有効ですが、ほとんどはv5で有効です) 。
次の2つの条件が満たされた場合、共有は観察可能な「ホット」になります。
シナリオ1:サブスクライバーの数が0を超えており、新しいサブスクリプションの前にオブザーバブルが完了していない
var shared = rx.Observable.interval(5000).take(2).share();
var startTime = Date.now();
var log = (x) => (value) => {
console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
};
var observer1 = shared.subscribe(log('observer1')),
observer2;
setTimeout(()=>{
observer2 = shared.subscribe(log('observer2'));
}, 3000);
// emission for both observer 1 and observer 2, with the samve value at startTime + 5 seconds
// another emission for both observers at: startTime + 10 seconds
シナリオ2:新しいサブスクリプションの前のサブスクライバーの数はゼロです。 「冷たくなる」
var shared = rx.Observable.interval(5000).take(2).share();
var startTime = Date.now();
var log = (x) => (value) => {
console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
};
var observer1 = shared.subscribe(log('observer1')),
observer2;
setTimeout(()=>{
observer1.unsubscribe();
}, 1000);
setTimeout(()=>{
observer2 = shared.subscribe(log('observer2')); // number of subscribers is 0 at this time
}, 3000);
// observer2's onNext is called at startTime + 8 seconds
// observer2's onNext is called at startTime + 13 seconds
シナリオ3:新しいサブスクリプションの前にオブザーバブルが完了したとき。 「冷たくなる」
var shared = rx.Observable.interval(5000).take(2).share();
var startTime = Date.now();
var log = (x) => (value) => {
console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
};
var observer1 = shared.subscribe(log('observer1')),
observer2;
setTimeout(()=>{
observer2 = shared.subscribe(log('observer2'));
}, 12000);
// 2 emission for observable 1, at startTime + 5 secs, and at startTime + 10secs
// 2 emissions for observable 2,at startTime + 12 + 5 secs, and at startTime + 12 + 10secs