観察可能な独自のサブスクライブされた2つの関数を作成します。シーケンス内の各要素に対して両方の関数を実行する予定ですが、最後の関数のみが実行されます。
let observer = null
const notificationArrayStream = Rx.Observable.create(function (obs) {
observer = obs;
return () => {}
})
function trigger(something) {
observer.next(something)
}
notificationArrayStream.subscribe((x) => console.log('a: ' + x))
notificationArrayStream.subscribe((x) => console.log('b: ' + x))
trigger('TEST')
期待される出力
a: TEST
b: TEST
実際の出力
b: TEST
JSBinは次のとおりです。 http://jsbin.com/cahoyey/edit?js,console
何故ですか?単一のObservableに複数の関数をサブスクライブさせるにはどうすればよいですか?
複数の関数が単一のObservableにサブスクライブするようにするには、そのObservableにサブスクライブするだけです。そして実際にそれはあなたがしたことです。
ただし、notificationArrayStream.subscribe((x) => console.log('b: ' + x))
が実行された後、observer
は(x) => console.log('b: ' + x))
、 そう observer.next
はb: TEST
。
したがって、基本的には、あなたの観察可能な作成が間違っています。 create
では、オブザーバーをパラメーターとして渡したため、値を渡すことができます。これらの値は、独自のロジックを通じて何らかの方法で生成する必要がありますが、ここでわかるように、ここでのロジックは間違っています。オブザーバーに値をプッシュする場合は、サブジェクトを使用することをお勧めします。
何かのようなもの:
const notificationArrayStream = Rx.Observable.create(function (obs) {
mySubject.subscribe(obs);
return () => {}
})
function trigger(something) {
mySubject.next(something)
}
あなたの場合は、単にSubject
を使用できます。 subject を使用すると、複数のオブザーバーと単一の実行を共有できますサブスクライバーのグループおよびソースのプロキシとして使用する場合。
本質的に、件名を使用した例です。
const subject = new Subject();
function trigger(something) {
subject.next(something);
}
subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));
trigger('TEST');
結果:
a: TEST
b: TEST
サブスクライブするタイミングとデータをブロードキャストするタイミングは関連していることに注意してください。購読する前にブロードキャストを送信した場合、このブロードキャストによる通知はありません。
function trigger(something) {
subject.next(something);
}
trigger('TEST');
subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));
結果:(空)
将来のサブスクライバーでも通知されるようにするには、代わりに ReplaySubject または BehaviorSubject を使用できます。
以下はReplaySubject
を使用した例です(キャッシュサイズ5で、過去から最大5つの値が記憶されます。これは、最後のみを記憶できるBehaviorSubjectとは対照的です。値):
const subject = new ReplaySubject(5); // buffer size is 5
function trigger(something) {
subject.next(something);
}
trigger('TEST');
subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));
結果:
a: TEST
b: TEST
サブスクライブするたびに、varobserverをオーバーライドしています。
trigger関数はこの1つの変数のみを参照するため、ログが1つしかないことは驚くことではありません。
変数を配列にすると、意図したとおりに動作します:JS Bin
let obs = [];
let foo = Rx.Observable.create(function (observer) {
obs.Push(observer);
});
function trigger(sth){
// console.log('trigger fn');
obs.forEach(ob => ob.next(sth));
}
foo.subscribe(function (x) {
console.log(`a:${x}`);
});
foo.subscribe(function (y) {
console.log(`b:${y}`);
});
trigger(1);
trigger(2);
trigger(3);
trigger(4);
よりクリーンなソリューションは、上記で提案したように、 Subject を使用することです。
ReplaySubjectに基づいてラッパークラスSubscribable <>を構築できます。 SubjectとObservableを管理するよりもクリーンです。
export class Subscribable<T> {
private valueSource: Subject = new ReplaySubject(1);
public value: Observable;
private _value: T;
constructor() {
this.value = this.valueSource.asObservable();
}
public set(val: T) {
this.valueSource.next(val);
this._value = val;
}
public get(): T {
return this._value;
}
}
使用法:
let arrayStream : Subscribable<TYPE> = new Subscribable<TYPE>();
…
public setArrayStream (value: TYPE) {
this.set(value);
}
値の変更を処理する:
arrayStream.value.subscribe(res => { /*handle it*/ });
元の記事: http://devinstance.net/articles/20170921/rxjs-subscribable
Subjectを使用する代わりに、 publishReplay()+ refCount()combo を使用して、observableが複数のサブスクライバーにマルチキャストできるようにすることもできます。
const notificationArrayStream = Rx.Observable.create(function (obs) {
observer = obs;
return () => {}
}).pipe(publishReplay(), refCount())