web-dev-qa-db-ja.com

RxJS Observableへの複数のサブスクリプション?

観察可能な独自のサブスクライブされた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に複数の関数をサブスクライブさせるにはどうすればよいですか?

37
cgross

複数の関数が単一のObservableにサブスクライブするようにするには、そのObservableにサブスクライブするだけです。そして実際にそれはあなたがしたことです。

ただし、notificationArrayStream.subscribe((x) => console.log('b: ' + x))が実行された後、observer(x) => console.log('b: ' + x))、 そう observer.nextb: TEST

したがって、基本的には、あなたの観察可能な作成が間違っています。 createでは、オブザーバーをパラメーターとして渡したため、値を渡すことができます。これらの値は、独自のロジックを通じて何らかの方法で生成する必要がありますが、ここでわかるように、ここでのロジックは間違っています。オブザーバーに値をプッシュする場合は、サブジェクトを使用することをお勧めします。

何かのようなもの:

const notificationArrayStream = Rx.Observable.create(function (obs) {
  mySubject.subscribe(obs);
  return () => {}
})

function trigger(something) {
  mySubject.next(something)
}
20
user3743222

Subject

あなたの場合は、単に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 または 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
53
Mobiletainment

サブスクライブするたびに、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 を使用することです。

4
Luca Bertolasi

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

0
yfranz

Subjectを使用する代わりに、 publishReplay()+ refCount()combo を使用して、observableが複数のサブスクライバーにマルチキャストできるようにすることもできます。

const notificationArrayStream = Rx.Observable.create(function (obs) {
  observer = obs;
  return () => {}
}).pipe(publishReplay(), refCount())
0
golfadas