RxJS のサブジェクトは、値を複数のオブザーバーにマルチキャストできる特別なタイプの Observable であるため、サブジェクトはマルチキャストですが、通常の Observable はユニキャストです (サブスクライブされた各オブザーバーには、個別に実行される Observable があります)。
コードでの定義:
export declare class Subject<T> extends Observable<T> implements SubscriptionLike {}
RxJS で一般的に使用される Subject には、通常の Subject、BehaviorSubject、AsyncSubject、ReplaySubject の 4 種類があります。
普通Subject
一般的な件名の例:
let subject: Subject<number> = new Subject<number>();
let count = 0;
let intervalId = setInterval(() => {
count++;
if (count < 3) {
subject.next(count);
} else {
subject.complete();
clearInterval(intervalId);
}
}, 1000);
subject.subscribe(
data => { console.log(`1st subscribe: ${data}`) },
(err) => { console.log(`1st subscribe err: ${err}`) },
() => { console.log(`1st subscribe complete`) });
setTimeout(() => {
subject.subscribe(
data => { console.log(`2nd subscribe: ${data}`) },
(err) => { console.log(`2nd subscribe err: ${err}`) },
() => { console.log(`2nd subscribe complete`) });
}, 2000);
setTimeout(() => {
subject.subscribe(
data => { console.log(`3rd subscribe: ${data}`) },
(err) => { console.log(`3rd subscribe err: ${err}`) },
() => { console.log(`3rd subscribe complete`) });
}, 5000);
操作結果:
効果は Hot Observables と同じであることがわかります.値が発行された後に追加されたサブスクリプションは、値とその前に発行された値を受け取ることができません. ただし、完了通知を受け取ることはできます。したがって、Subject は Hot Observable です。
行動主体
サブジェクトの 1 つのバリアントは、「現在の値」の概念を持つ BehaviorSubject です。コンシューマーに送信された最新の値を保持します。そして、新しいオブザーバーがサブスクライブすると、すぐに BehaviorSubject から「現在の値」を受け取ります。
let subject: BehaviorSubject<number> = new BehaviorSubject<number>(0);
let count = 0;
let intervalId = setInterval(() => {
count++;
if (count < 3) {
subject.next(count);
} else {
subject.complete();
clearInterval(intervalId);
}
}, 1000);
subject.subscribe(
data => { console.log(`1st subscribe: ${data}`) },
(err) => { console.log(`1st subscribe err: ${err}`) },
() => { console.log(`1st subscribe complete`) });
setTimeout(() => {
subject.subscribe(
data => { console.log(`2nd subscribe: ${data}`) },
(err) => { console.log(`2nd subscribe err: ${err}`) },
() => { console.log(`2nd subscribe complete`) });
}, 2100);
setTimeout(() => {
subject.subscribe(
data => { console.log(`3rd subscribe: ${data}`) },
(err) => { console.log(`3rd subscribe err: ${err}`) },
() => { console.log(`3rd subscribe complete`) });
}, 5000);
操作結果:
本体が 2 を送信し、値 2 (「現在の値」) を受信した後、2 番目のサブスクリプションが追加されていることがわかります。
一般的なサブジェクトとの違いをよりよく反映するために、サブジェクトがデータ プッシュを完了していないと考えて、上記のコードの subject.complete(); をコメント アウトすることができます。
この時点で、一般的な Subject の実行結果を使用します。
2回目、3回目の定期購読追加後、本体からデータが送られてこないので印刷されません。
BehaviorSubject を使用した結果:
2 番目と 3 番目のサブスクリプションが追加された後、本体はデータを送信していませんが、両方とも本体の現在の値 (最後に送信されたデータ) を受信しているため、すべて 2 が出力されます。
リプレイ件名
ReplaySubject は、古い値を新しいサブスクライバーに送信できるという点で BehaviorSubject に似ていますが、Observable の実行の一部を記録することもできます。
let subject: ReplaySubject<number> = new ReplaySubject<number>(2);
let count = 0;
let intervalId = setInterval(() => {
count++;
if (count < 5) {
subject.next(count);
} else {
subject.complete();
clearInterval(intervalId);
}
}, 1000);
subject.subscribe(
data => { console.log(`1st subscribe: ${data}`) },
(err) => { console.log(`1st subscribe err: ${err}`) },
() => { console.log(`1st subscribe complete`) });
setTimeout(() => {
subject.subscribe(
data => { console.log(`2nd subscribe: ${data}`) },
(err) => { console.log(`2nd subscribe err: ${err}`) },
() => { console.log(`2nd subscribe complete`) });
}, 4000);
setTimeout(() => {
subject.subscribe(
data => { console.log(`3rd subscribe: ${data}`) },
(err) => { console.log(`3rd subscribe err: ${err}`) },
() => { console.log(`3rd subscribe complete`) });
}, 8000);
操作結果:
後で追加されたサブスクリプションは、最近開始された 2 つのデータ値を受け取り、完了の通知を受け取っていることがわかります。
AsyncSubject
AsyncSubject は、Observable の実行が完了する (complete() を実行する) ときに、実行の最後の値のみをオブザーバーに送信するもう 1 つの Subject バリアントです。
let subject: AsyncSubject<number> = new AsyncSubject<number>();
let count = 0;
let intervalId = setInterval(() => {
count++;
if (count < 5) {
subject.next(count);
} else {
subject.complete();
clearInterval(intervalId);
}
}, 1000);
subject.subscribe(
data => { console.log(`1st subscribe: ${data}`) },
(err) => { console.log(`1st subscribe err: ${err}`) },
() => { console.log(`1st subscribe complete`) });
setTimeout(() => {
subject.subscribe(
data => { console.log(`2nd subscribe: ${data}`) },
(err) => { console.log(`2nd subscribe err: ${err}`) },
() => { console.log(`2nd subscribe complete`) });
}, 3000);
setTimeout(() => {
subject.subscribe(
data => { console.log(`3rd subscribe: ${data}`) },
(err) => { console.log(`3rd subscribe err: ${err}`) },
() => { console.log(`3rd subscribe complete`) });
}, 6000);
操作結果:
すべてのサブスクリプションは、本体が完了する前に送信された最後のデータのみを受信したことがわかります。