Reaktivní vs Proaktivní programování s RxJS

(Ben Copeland) (25. března , 2020)

Pokud používáme knihovny ReactiveX, jako je RxJS, víme, že technicky implementujeme řešení reaktivního programování – používáme koncept pozorovatelných proudů RxJS a náš kód reaguje na nové události v proudu. Přesto, i když používáme reaktivní knihovnu, je možné náš software navrhnout spíše podle proaktivního paradigmatu než podle reaktivního. Tyto knihovny nám však mnohem lépe poslouží, pokud máme reaktivní rozpoložení.

Pojďme chvíli identifikovat rozdíl mezi proaktivním a reaktivním přístupem. Pod pojmem proaktivní mám na mysli přístup, při kterém si vydavatel (nebo subjekt) je vědom externích předplatitelů a jejich požadovaných stavů a ​​posílá aktualizace známým předplatitelům. Spojení se spotřebitelem probíhá na straně vydavatele. Pod pojmem reaktivní mám na mysli přístup, při kterém předplatitel obdrží aktualizaci a zpracovává ji sám.

Zvažte nedávný scénář, se kterým jsme se setkali na IQueue pro kliniky. Máme aplikaci Angular, která silně využívá RxJS, a chtěli jsme publikovat každou změnu, která se objeví v ngOnChanges háku životního cyklu komponenty, na stream, který by předplatitelé mohli spotřebovat.

Zde je zjednodušený příklad, ve kterém máme komponentu se třemi @Input vlastnostmi a máme některé komponenty, které chtějí sledovat objekt, který má nejnovější hodnotu každé z tři vlastnosti.

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 });
}
}
}

Ve výše uvedeném příkladu vytvoříme objekt s každou ze tří možných vlastností pro ukládání do mezipaměti, poté na ngOnChanges sloučíme aktualizace z kterékoli ze tří vlastností do tohoto objektu a aktualizujeme stream o nejnovější hodnotu kombinovaného objektu. Jedná se o proaktivní přístup – subjekt zná záměr pozorovatele. Pokud je přidán jiný pozorovatel, který má jiný záměr, nebo pokud se změní záměr aktuálního pozorovatele, je nutné změnit implementaci předmětu.

Výše ​​uvedený přístup je v podstatě tím, čím jsme začali, pak jsme šli dále jej refaktorovat, aby byla reaktivnější. Aby k tomu mohlo dojít, potřebovali jsme, aby subjekt jednoduše zveřejnil nejnovější hodnotu bez jakékoli znalosti spotřebitelů. Následuje aktualizovaná verze dřívější komponenty, která publikuje pouze aktuální aktualizace.

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

changes$: Subject = new Subject();

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

A potom zpracováme agregaci do jednoho objektu ve třídě, která spotřebovává pozorovatelný.

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
);

Pozorovatel nyní publikuje pouze nové události a předplatitel využívá jeden z mnoha výkonných kanálů RxJS zvaných skenování, aby udržel akumulovaný stav nejnovější hodnoty všech možných vlastností přicházejících streamem. Přemýšlejte o skenování jako o redukční funkci, která při každé události vydává nejnovější kumulovanou hodnotu. Po refaktoringu tedy máme předmět obecného účelu, který odesílá všechny možné ngOnChanges události. Pokud je přidáno více @Inputs, přirozeně se odešle i tyto. Všichni předplatitelé, kteří poslouchají stream, mohou dělat to, co považují za vhodné s streamem události – ať už se jedná o hromadění objektu všech událostí, nebo pouze o poslech změn u jedné vlastnosti.

Zatímco RxJS dává Pokud použijeme nástroje pro reaktivní programování, je stále možné navrhnout kód, který se řídí proaktivnějším paradigmatem. Abychom byli reaktivnější, můžeme udržovat naše publikování co nejagnostickější a umožnit nebo předplatná implementovat složitější logiku.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *