RxJSを使用したリアクティブプログラミングとプロアクティブプログラミング

投稿日:

(ベンコープランド)(3月25日) 、2020)

RxJSなどのReactiveXライブラリを使用している場合、リアクティブプログラミングソリューションを技術的に実装していることがわかります。RxJSの監視可能なストリームの概念を使用し、コードは新しいイベントに反応しますストリームで。ただし、リアクティブライブラリを使用する場合でも、リアクティブパラダイムではなくプロアクティブパラダイムに従ってソフトウェアを設計することができます。ただし、リアクティブな考え方があれば、これらのライブラリの方がはるかに優れています。

プロアクティブなアプローチとリアクティブなアプローチの違いを確認するために、少し時間を取ってみましょう。 プロアクティブとは、パブリッシャー(またはサブジェクト)が外部サブスクライバーとその望ましい状態を認識し、既知のサブスクライバーに更新をプッシュするアプローチを指します。消費者との結合は、発行者側で発生します。 reactive とは、サブスクライバーが更新を受信して​​それを独自に処理するアプローチを指します。

IQueue forClinicsで発生した最近のシナリオについて考えてみます。 RxJSを多用するAngularアプリがあり、コンポーネントのngOnChangesライフサイクルフックで発生する各変更をサブスクライバーが消費できるストリームに公開したいと考えていました。

これは単純化された例です。3つの@Inputプロパティを持つコンポーネントがあり、それぞれの最新の値を持つオブジェクトを追跡したいコンポーネントがいくつかあります。 3つのプロパティ。

interface IChanges { a: string; b: string; c: string; }

@Component({...})
class SomeComponent {
@Input() a;
@Input() b;
@Input() c;

changes$: BehaviorSubject = new BehaviorSubject({
a: null,
b: null,
c: null,
});

allLatestChanges: IChanges;

ngOnChanges(changes: SimpleChanges) {
if (changes.a) {
changes$.next(Object.assign(allLatestChanges, { a: changes.a.currentValue });
}
if (changes.b) {
changes$.next(Object.assign(allLatestChanges, { b: changes.b.currentValue });
}
if (changes.c) {
changes$.next(Object.assign(allLatestChanges, { c: changes.c.currentValue });
}
}
}

上記の例では、キャッシュに使用できる3つのプロパティのそれぞれを使用してオブジェクトを作成し、次にngOnChanges、3つのプロパティのいずれかからの更新をそのオブジェクトにマージし、結合されたオブジェクトの最新の値でストリームを更新します。これはプロアクティブなアプローチです—被験者はオブザーバーの意図を知っています。意図が異なる別のオブザーバーが追加された場合、または現在のオブザーバーの意図が変更された場合は、サブジェクトの実装を変更する必要があります。

上記のアプローチは基本的に私たちが始めたものであり、次に進みました。それをより反応的にするためにそれをリファクタリングするために。そのためには、消費者の知識がなくても、主題が最​​新の価値を単に公開する必要がありました。以下は、現在の更新のみを公開する以前のコンポーネントの更新バージョンです。

@Component({...})
class SomeComponent {
@Input() a;
@Input() b;
@Input() c;

changes$: Subject = new Subject();

ngOnChanges(changes: SimpleChanges) {
changes$.next(changes);
}
}

次に、消費するクラス内の単一のオブジェクトへの集約を処理します。オブザーバブル。

defaultAcc = {
a: null,
b: null,
c: null,
}

allChanges$ = changes$
.pipe(
scan((acc, curr) =>
Object.assign(acc, Object.fromEntries(
Object.entries(curr).map((k,v) => { [k]: v.currentValue })
)
)), defaultAcc
);

現在、オブザーバブルは新しいイベントのみを公開しており、サブスクライバーはスキャンと呼ばれるRxJSの多くの強力なパイプの1つを利用して、蓄積された状態を維持しています。ストリームを介して来るすべての可能なプロパティの最新の値の。スキャンは、すべてのイベントで最新の累積値を出力するリデュース関数と考えてください。したがって、リファクタリング後、考えられるすべてのngOnChangesイベントをディスパッチする汎用サブジェクトがあります。 @Inputsがさらに追加されると、当然それらもディスパッチされます。ストリームをリッスンしているサブスクライバーは、すべてのイベントのオブジェクトを蓄積する場合でも、単一のプロパティの変更のみをリッスンする場合でも、イベントストリームに適していると思われることを実行できます。

RxJSはリアクティブプログラミングを行うためのツールを使用しても、よりプロアクティブなパラダイムに従うコードを設計することは可能です。より反応的にするために、公開を可能な限り不可知論的に保ち、サブスクリプションがより複雑なロジックを実装できるようにすることができます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です