Programmation réactive vs proactive avec RxJS

(Ben Copeland) (25 mars , 2020)

Si nous utilisons des bibliothèques ReactiveX telles que RxJS, nous savons que nous implémentons techniquement une solution de programmation réactive – nous utilisons le concept de RxJS de flux observables, et notre code réagit aux nouveaux événements dans le ruisseau. Pourtant, même si nous utilisons une bibliothèque réactive, il est possible de concevoir notre logiciel selon un paradigme plus proactif plutôt que réactif. Cependant, nous sommes bien mieux servis par ces bibliothèques si nous avons un état d’esprit réactif.

Prenons un moment pour identifier la distinction entre une approche proactive et réactive. Par proactif , je fais référence à une approche dans laquelle léditeur (ou le sujet) est au courant des abonnés externes et de leurs états souhaités, et envoie des mises à jour aux abonnés connus. Le couplage avec le consommateur se fait du côté de léditeur. Par réactif je fais référence à une approche dans laquelle labonné reçoit une mise à jour et la gère seul.

Considérons un scénario récent que nous avons rencontré sur IQueue for Clinics. Nous avons une application Angular qui utilise fortement RxJS et nous voulions publier chaque changement qui survient dans le cycle de vie ngOnChanges dun composant à un flux que les abonnés pourraient consommer.

Voici un exemple simplifié, dans lequel nous avons un composant avec trois propriétés @Input, et nous avons des composants qui veulent garder une trace dun objet qui a la valeur la plus récente de chacun des les trois propriétés.

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

Dans lexemple ci-dessus, nous créons un objet avec chacune des trois propriétés possibles pour la mise en cache, puis sur ngOnChanges, nous fusionnons les mises à jour de lune des trois propriétés dans cet objet et nous mettons à jour le flux avec la dernière valeur de lobjet combiné. Il sagit dune approche proactive – le sujet connaît lintention de lobservateur. Si un autre observateur est ajouté qui a une intention différente, ou si lintention de lobservateur actuel change, limplémentation du sujet doit être modifiée.

Lapproche ci-dessus est essentiellement celle avec laquelle nous avons commencé, alors nous sommes allés sur pour le refactoriser pour le rendre plus réactif. Pour cela, il fallait que le sujet publie simplement la dernière valeur sans aucune connaissance des consommateurs. Ce qui suit est une version mise à jour du composant précédent qui ne publie que les mises à jour actuelles.

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

changes$: Subject = new Subject();

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

Ensuite, nous gérons lagrégation en un seul objet dans la classe qui consomme lobservable.

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

Maintenant, lobservable ne publie que de nouveaux événements, et labonné exploite lun des nombreux canaux puissants de RxJS appelé scan pour conserver un état accumulé des dernières valeurs de toutes les propriétés possibles qui transitent par le flux. Considérez le balayage comme une fonction de réduction qui génère la dernière valeur accumulée à chaque événement. Donc, après le refactoring, nous avons un sujet à usage général qui distribue tous les événements ngOnChanges possibles. Si plus de @Inputs sont ajoutés, il les enverra naturellement aussi. Tous les abonnés qui écoutent le flux peuvent faire ce quils jugent bon avec le flux dévénements – quil sagisse daccumuler un objet de tous les événements ou découter uniquement les modifications sur une seule propriété.

Alors que RxJS donne nous les outils pour faire de la programmation réactive, il est encore possible de concevoir du code qui suit un paradigme plus proactif. Pour être plus réactifs, nous pouvons garder notre publication aussi agnostique que possible et permettre aux abonnements dimplémenter une logique plus compliquée.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *