Existe-t-il un opérateur ou une composition Rx pour garantir la dernière exécution de la logique pour chaque émission observable?
Supposons le contexte suivant:
filter ()
pour ignorer certaines émissions doAlways()
Veuillez vous référer aux commentaires numérotés dans l'exemple de code ci-dessous
Remarques:
finalize ()
exigerait que la séquence se termine (enfreint la p.1) iif ()
ou normal if
à l'intérieur de switchMap ()
est une option mais rend le code plus illisible Extrait de code pour illustrer: L'étape (3) doit toujours s'exécuter, par itération, en dernier, c'est-à-dire que nous voulons toujours commencer et terminer la connexion dans un doAlways () -like opérateur au lieu de
tap()
import { of, interval } from 'rxjs'; import { tap, filter, switchMap } from 'rxjs/operators'; const dataService = { update: (z) => of(z /*posts data to back-end*/) }; const sub = interval(1000).pipe( // <-- (1) tap(a => console.log('starting', a)), filter(b => b % 100 === 0), // <-- (2) switchMap(c => dataService.update(c)), tap(d => console.log('finishing', d)) // <-- (3) should execute always even (2) ) .subscribe(x => console.log(x));
3 Réponses :
Un tel opérateur n'existe pas, et c'est parce qu'il ne peut pas exister. Une fois que vous avez filtré une valeur, l'observable qui en résulte ne l'émet plus. Tout opérateur "en aval" ne connaît tout simplement pas son existence.
Pour illustrer, vous avez inclus un switchMap à un service, qui dépend de la valeur émise. Pour des raisons évidentes cet opérateur qui ne peut pas être appliqué logiquement s'il n'y a pas de valeur à activer.
Pensez à l'observable comme à un tapis roulant sur lequel vous placez des objets. Chaque opérateur est une pièce à travers laquelle passe la ceinture. À l'intérieur de chaque pièce, un travailleur peut décider quoi faire de chaque article: le modifier, le retirer, mettre de nouveaux articles à la place, etc. avant eux ou ce qui a été fait là-bas.
Pour réaliser ce que vous voulez, le travailleur de la dernière salle devrait être au courant d'un objet qu'il n'a jamais reçu, ce qui nécessiterait des connaissances supplémentaires qu'il ne possède pas.
Parfois, je pense que RxJS est juste Factorio mais plus illisible et moins débuggable
Je trouve cela extrêmement confortable à lire par rapport aux méthodes plus traditionnelles :-) La débuggabilité est un peu un problème, mais j'ai toujours réussi avec la journalisation des taps. Mais les préférences personnelles diffèrent.
Confortable pour ceux qui connaissent les mots, bien sûr ;-)
Cependant, je faisais référence à ce jeu: factorio.com On pourrait recréer votre analogie dans ce jeu. Peut-être illisible n'est pas le meilleur terme, disons «compréhensible»
Oui, si vous ne comprenez pas les concepts ou les mots, c'est presque impossible à comprendre. Mais je préférerais que les gens l'apprennent plutôt que de le rejeter à cause de cela. Je vérifierai ce lien plus tard!
Non, ce que vous demandez n'est pas possible car les notifications filtrées ne seront jamais transmises. Vous auriez besoin d'un type de notification totalement nouveau qui n'est consommé par aucun autre opérateur que celui que vous décrivez.
Voici maintenant une idée qui n'est probablement pas recommandée. Vous pouvez abuser de la notification error
pour ignorer certains opérateurs, mais cela interférera avec toute autre gestion d'erreur, ce n'est donc pas quelque chose que vous devriez faire ...
const sub = interval(1000).pipe( tap(a => console.log('starting', a)), mergeMap(b => b % 100 === 0 ? of(b) : throwError(b)), switchMap(c => dataService.update(c)), catchError(b => of(b)), tap(d => console.log('finishing', d)) )
Notez que nous n'utilisons pas de filtre
mais mappons vers une notification next
ou error
en fonction de la condition. Les erreurs seront naturellement ignorées par la plupart des opérateurs et consommées par tap
, subscribe
ou catchError
. C'est une façon de mettre une balise sur l'élément pour que les travailleurs sachent qu'ils ne doivent pas y toucher (dans l'analogie décrite par Ingo)
C'est pourquoi la condition se lit comme suit: "comme filtre" et non "filtre". Filtrer pour arrête sûrement tout flux supplémentaire, mais le sens est un moyen de sauter par-dessus les étapes indésirables pour les étapes d'itération particulières sans rendre iif-s ou d'autres choses qui rendent le code trop bouclé. Si .doAlways () - comme existait - le problème serait résolu
Eh bien, un seul opérateur ne pouvait rien faire de tel, c'est plus une restriction en raison des types de notifications possibles
Je le diviserais pour 2 flux avec partition
, et ils les fusionneraient.
https://stackblitz.com/edit/rxjs-8z9jit?file=index.ts
import { of, interval, merge } from 'rxjs'; import { tap, switchMap, partition, share } from 'rxjs/operators'; const dataService = { update: z => of(z /*posts data to back-end*/) }; const [sub, rest] = interval(1000).pipe( tap(a => console.log('starting', a)), share(), partition(b => b % 2 === 0) ); merge( sub.pipe( switchMap(c => dataService.update(c)), tap(() => console.log('Ok')) ), rest ) .pipe(tap(d => console.log('finishing', d))) .subscribe(x => console.log(x));
p >
OP souhaite que la notification atteigne
appuyez sur
même si elle a été filtrée auparavant. Ce ne sera pas possible cependant.