回答:
BehaviorSubjectはサブジェクトの一種であり、サブジェクトは特別なタイプのオブザーバブルなので、他のオブザーバブルと同様にメッセージをサブスクライブできます。BehaviorSubjectの独自の機能は次のとおりです。
next()
onnext
getValue()
。オブザーバブルと比較したサブジェクトの固有の特徴は次のとおりです。
さらに、のasObservable()
メソッドを使用して、行動主体からオブザーバブルを取得できますBehaviorSubject
。
ObservableはジェネリックでありBehaviorSubject
、BehaviorSubjectは特定の品質のオブザーバブルであるため、技術的にはObservableのサブタイプです。
BehaviorSubjectの例:
// Behavior Subject
// a is an initial value. if there is a subscription
// after this, it would get "a" value immediately
let bSubject = new BehaviorSubject("a");
bSubject.next("b");
bSubject.subscribe(value => {
console.log("Subscription got", value); // Subscription got b,
// ^ This would not happen
// for a generic observable
// or generic subject by default
});
bSubject.next("c"); // Subscription got c
bSubject.next("d"); // Subscription got d
通常の件名の例2:
// Regular Subject
let subject = new Subject();
subject.next("b");
subject.subscribe(value => {
console.log("Subscription got", value); // Subscription wont get
// anything at this point
});
subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d
観測可能で、両方から作成することが可能Subject
とBehaviorSubject
使用しますsubject.asObservable()
。
唯一の違いは、observable using next()
メソッドに値を送信できないことです。
Angularサービスでは、BehaviorSubject
コンポーネントと動作サブジェクトがサービスのコンポーネントがこのデータへのサブスクリプション以降の新しい更新がない場合でも、最後に更新されたデータを確実に受信する前に、Angleサービスが初期化されることが多いため、データサービスに使用します。
1つの非常に重要な違い。Observableは単なる関数なので、状態はありません。そのため、新しいObserverごとに、observable createコードを繰り返し実行します。これは結果として:
コードはオブザーバーごとに実行されます。HTTP呼び出しの場合、オブザーバーごとに呼び出されます
これは大きなバグと非効率を引き起こします
BehaviorSubject(またはSubject)は、オブザーバーの詳細を格納し、コードを1回だけ実行して、その結果をすべてのオブザーバーに提供します。
例:
JSBin:http ://jsbin.com/qowulet/edit?js,console
// --- Observable ---
let randomNumGenerator1 = Rx.Observable.create(observer => {
observer.next(Math.random());
});
let observer1 = randomNumGenerator1
.subscribe(num => console.log('observer 1: '+ num));
let observer2 = randomNumGenerator1
.subscribe(num => console.log('observer 2: '+ num));
// ------ BehaviorSubject/ Subject
let randomNumGenerator2 = new Rx.BehaviorSubject(0);
randomNumGenerator2.next(Math.random());
let observer1Subject = randomNumGenerator2
.subscribe(num=> console.log('observer subject 1: '+ num));
let observer2Subject = randomNumGenerator2
.subscribe(num=> console.log('observer subject 2: '+ num));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.3/Rx.min.js"></script>
出力:
"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"
を使用Observable.create
して、オブザーバーごとに異なる出力がどのように作成されたかを観察しますがBehaviorSubject
、すべてのオブザーバーに同じ出力を与えました。これは重要。
その他の違いをまとめました。
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Observable ┃ BehaviorSubject/Subject ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Is just a function, no state ┃ Has state. Stores data in memory ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Code run for each observer ┃ Same code run ┃
┃ ┃ only once for all observers ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Creates only Observable ┃Can create and also listen Observable┃
┃ ( data producer alone ) ┃ ( data producer and consumer ) ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Usage: Simple Observable with only ┃ Usage: ┃
┃ one Obeserver. ┃ * Store data and modify frequently ┃
┃ ┃ * Multiple observers listen to data ┃
┃ ┃ * Proxy between Observable and ┃
┃ ┃ Observer ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
KnockoutJS's ko.observable()
すぐにRx.BehaviorSubject
比べてより多くの類似点を目にするRx.Observable
観察可能と対象の両方が観察可能であることは、観察者がそれらを追跡できることを意味します。しかし、どちらにもいくつかのユニークな特徴があります。さらに、合計3種類のサブジェクトがあり、それぞれに固有の特性があります。それぞれを理解してみましょう。
この実用的な例は、こちらのstackblitzにあります。 (実際の出力を確認するには、コンソールを確認する必要があります)
Observables
彼らは寒いです。少なくとも1人のオブザーバーがいるときにコードが実行されます。
データのコピーを作成: Observableは、各オブザーバーのデータのコピーを作成します。
単方向:オブザーバーは、observable(origin / master)に値を割り当てることができません。
Subject
ホットです。オブザーバーがいない場合でも、コードが実行され、値がブロードキャストされます。
データの共有:すべてのオブザーバー間で同じデータが共有されます。
双方向:オブザーバーは、observable(origin / master)に値を割り当てることができます。
サブジェクトを使用している場合、オブザーバーの作成前にブロードキャストされるすべての値を見逃します。だからここにリプレイ件名が来ます
ReplaySubject
ホットです。オブザーバーがいない場合でも、コードが実行され、値がブロードキャストされます。
データの共有:すべてのオブザーバー間で同じデータが共有されます。
双方向:オブザーバーは、observable(origin / master)に値を割り当てることができます。プラス
メッセージストリームの再生:再生サブジェクトをサブスクライブすると、ブロードキャストされたすべてのメッセージを受信します。
サブジェクトとリプレイサブジェクトでは、初期値を観測可能に設定することはできません。だからここに行動の主題があります
BehaviorSubject
ホットです。オブザーバーがいない場合でも、コードが実行され、値がブロードキャストされます。
データの共有:すべてのオブザーバー間で同じデータが共有されます。
双方向:オブザーバーは、observable(origin / master)に値を割り当てることができます。プラス
メッセージストリームの再生:再生サブジェクトをサブスクライブすると、ブロードキャストされたすべてのメッセージを受信します。
初期値を設定できます:デフォルト値でオブザーバブルを初期化できます。
ReplaySubject
には履歴があり、一連の(古い)値をブロードキャストまたは送信できることに言及する価値があります。bufferが1に設定されている場合のみ、と同様に動作しBehaviorSubject
ます。
Observableオブジェクトは、プッシュベースのコレクションを表します。
ObserverおよびObservableインターフェースは、オブザーバーデザインパターンとも呼ばれる、プッシュベースの通知のための一般化されたメカニズムを提供します。Observableオブジェクトは、通知を送信するオブジェクト(プロバイダー)を表します。Observerオブジェクトは、それらを受け取るクラス(オブザーバー)を表します。
Subjectクラスは、ObserverとObserverの両方であるという意味で、ObservableとObserverの両方を継承します。サブジェクトを使用してすべてのオブザーバーをサブスクライブしてから、サブジェクトをバックエンドデータソースにサブスクライブできます。
var subject = new Rx.Subject();
var subscription = subject.subscribe(
function (x) { console.log('onNext: ' + x); },
function (e) { console.log('onError: ' + e.message); },
function () { console.log('onCompleted'); });
subject.onNext(1);
// => onNext: 1
subject.onNext(2);
// => onNext: 2
subject.onCompleted();
// => onCompleted
subscription.dispose();
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.mdの詳細
例に見られないのは、asObservableを介してBehaviorSubjectをObservableにキャストすると、サブスクリプションで最後の値を返す動作を継承することです。
多くの場合、ライブラリはフィールドを観察可能として公開するため(つまり、Angular2のActivatedRouteのparams)、これは難しいですが、SubjectまたはBehaviorSubjectを舞台裏で使用する場合があります。彼らが使用するものは、サブスクライブの動作に影響します。
こちらをご覧くださいhttp://jsbin.com/ziquxapubo/edit?html,js,console
let A = new Rx.Subject();
let B = new Rx.BehaviorSubject(0);
A.next(1);
B.next(1);
A.asObservable().subscribe(n => console.log('A', n));
B.asObservable().subscribe(n => console.log('B', n));
A.next(2);
B.next(2);
観測可能で、一方、あなただけ購読することができ、被験者が両方のパブリッシュおよびサブスクライブすることができます。
したがって、サブジェクトを使用すると、サービスをパブリッシャーとサブスクライバーの両方として使用できます。
今のところ、私はあまり上手ではないのでObservable
、の例だけを紹介しますSubject
。
Angular CLIの例を使って理解を深めましょう。以下のコマンドを実行します。
npm install -g @angular/cli
ng new angular2-subject
cd angular2-subject
ng serve
の内容を次のものに置き換えますapp.component.html
。
<div *ngIf="message">
{{message}}
</div>
<app-home>
</app-home>
コマンドng g c components/home
を実行してホームコンポーネントを生成します。の内容を次のものに置き換えますhome.component.html
。
<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>
#message
ここでのローカル変数です。のクラスにプロパティmessage: string;
を追加しますapp.component.ts
。
このコマンドを実行しますng g s service/message
。これにより、でサービスが生成されsrc\app\service\message.service.ts
ます。このサービスをアプリに提供します。
にインポートSubject
しMessageService
ます。件名も追加します。最終的なコードは次のようになります。
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MessageService {
public message = new Subject<string>();
setMessage(value: string) {
this.message.next(value); //it is publishing this value to all the subscribers that have already subscribed to this message
}
}
次に、このサービスを注入しhome.component.ts
、そのインスタンスをコンストラクタに渡します。これapp.component.ts
もやってください。の値を#message
サービス関数に渡すには、このサービスインスタンスを使用しますsetMessage
。
import { Component } from '@angular/core';
import { MessageService } from '../../service/message.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
constructor(public messageService:MessageService) { }
setMessage(event) {
console.log(event.value);
this.messageService.setMessage(event.value);
}
}
内部でapp.component.ts
、サブスクライブおよびサブスクライブ解除(メモリリークを防止するため)しますSubject
。
import { Component, OnDestroy } from '@angular/core';
import { MessageService } from './service/message.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
message: string;
subscription: Subscription;
constructor(public messageService: MessageService) { }
ngOnInit() {
this.subscription = this.messageService.message.subscribe(
(message) => {
this.message = message;
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
それでおしまい。
ここで、内部#message
に入力された値はすべて内部に出力home.component.html
され{{message}}
ますapp.component.html
app.component.ts
behaviourService.setName("behaviour");
behaviour.service.ts
private name = new BehaviorSubject("");
getName = this.name.asObservable();`
constructor() {}
setName(data) {
this.name.next(data);
}
custom.component.ts
behaviourService.subscribe(response=>{
console.log(response); //output: behaviour
});
BehaviorSubjectとObservable:RxJSにはオブザーバーとオブザーバブルがあり、Rxjsはデータストリームで使用する複数のクラスを提供し、そのうちの1つはBehaviorSubjectです。
オブザーバブル:オブザーバブルは、時間の経過に伴う複数の値のレイジーコレクションです。
BehaviorSubject:初期値を必要とし、現在の値を新しいサブスクライバーに送信するサブジェクト。
// RxJS v6+
import { BehaviorSubject } from 'rxjs';
const subject = new BehaviorSubject(123);
//two new subscribers will get initial value => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);
//two subscribers will get new value => output: 456, 456
subject.next(456);
//new subscriber will get latest value (456) => output: 456
subject.subscribe(console.log);
//all three subscribers will get new value => output: 789, 789, 789
subject.next(789);
// output: 123, 123, 456, 456, 456, 789, 789, 789
Observablesは、水が流れるパイプと考えてください。水が流れる場合と流れない場合があります。いくつかのケースでは、あなたが実際にそれで常に水を持っている配管を必要とするかもしれない、あなたは常に関係なく、それがどのように小さな水が含まれていない特殊なパイプを作成することによってこれを行うことができ、この特別なパイプを呼び出すことができますBehaviorSubjectをあなたがあることを起こる場合は、あなたのコミュニティの給水プロバイダーであれば、新しく設置したパイプが機能することを知っていれば、夜は安らかに眠ることができます。
技術的に言えば、Observableに常に値が必要なユースケースに遭遇する可能性があります。おそらく、入力テキストの値を経時的に取得したい場合は、BehaviorSubjectのインスタンスを作成して、この種の動作を保証できます。
const firstNameChanges = new BehaviorSubject("<empty>");
// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");
次に、「値」を使用して、時間の経過に伴う変化をサンプリングできます。
firstNameChanges.value;
これは、後でObservableを組み合わせるときに便利です。BehaviorSubjectとしてストリームのタイプを確認することで、ストリームが少なくとも1回だけ発火またはシグナル通知されるようにすることができます。