1
votes

Comment aplatir les appels imbriqués dans RXJS et enfin appeler un dernier appel?

Comment pouvons-nous aplatir au mieux les appels ci-dessous. Nouveau sur RxJS, essayant de comprendre comment il devrait être simplifié. Lisez flatMap, forkJoin, switchMap et mergeMap, sans trouver le bon chemin pour l'intégrer ci-dessous et ne pas savoir ce qui est le meilleur dans le scénario ci-dessous.

const useful = [];

a.get('abc').
subscribe((abcdatas) => {

   abcdatas.forEach(abcdata => {
     if(abcdata.exist) {
        b.get('def').
        subscribe((defdatas) => {
           useful.push(defdatas.someval);
        });
      } 
   });

 })

if(useful.length) {
 c.get('ghi').
 subscribe((ghidata) => {
   completed...
 });
}

Mise à jour

Mise à jour de ma question ici et merci pour toutes les réponses. L'utile est un tableau global de résultats qui devrait être rempli à partir d'un appel imbriqué dans mon cas. Et il devrait être passé au dernier appel enfin.

Étapes que j'essaye:

  1. a.get () => renvoie adata
  2. b.get (adataset) => devrait effectuer une requête pour chaque adataset si adataset a un attribut exist et également remplir un tableau utile qui sera utilisé plus tard
  3. c.get (utile) => devrait se déclencher et se terminer.


0 commentaires

3 Réponses :


1
votes

Utilisez une fonction de mappage telle que switchMap ou mergeMap pour mapper le résultat d'une demande à la demande suivante. Utilisez forkJoin pour exécuter plusieurs requêtes simultanément.

Donc, pour un scénario un à plusieurs, l'idée générale est:

useful = [];

a.get('abc').pipe(
  switchMap(abcdatas => forkJoin(getUseFulRequests(abcdatas))),
  tap(useful => useful.forEach(u => this.useful.push(u))),
  switchMap(useful => useful.length ? c.get('ghi') : EMPTY)
).subscribe((ghidata) => {
  completed...
});


function getUseFulRequests(abcdatas: AbcData[]): Observable<SomeVal>[] {
  return abcdatas.reduce((acc, abcdata) => {
    if (abcdata.exist) {
      const request = b.get('def').pipe(
        map(defdatas => defdatas.someval)
      )
      acc.push(request);
    }
    return acc;
  }, []);
}

Pour votre cas, ce serait quelque chose comme:

firstRequest().pipe(
  switchMap(results => forkJoin(results.map(r => nextRequest(r))))
)

Cela n'émettra rien si getUseFulRequests(abcdatas) renvoie un tableau vide ou useful.length == 0 .


5 commentaires

Appréciez votre réponse


utile n'est pas seulement pour les requêtes utiles, c'est un tableau formé par le deuxième appel ibget ()


@MithunShreevatsa vous pouvez utiliser tap pour remplir votre tableau global à partir d'une réponse intermédiaire.


Exemple s'il vous plaît, comme je l'ai dit, je suis nouveau et cela prend du temps pour moi de sortir d'axios et d'async, d'attendre et de promettre


merci, j'ai appris quelque chose de très utile de votre réponse et m'appelle clairement :)



1
votes

Je pense que la meilleure façon de gérer cela sera d'utiliser des observables d'ordre supérieur

Considérez ci-dessous le code

useful$ = a.get('abc').pipe(
  mergeMap(abcdatas => 
    abcdata.exist ? forkJoin(abcdatas.map(abcdata => b.get('def'))) : of(undefined)
  ),
  map(defdatas => defdatas.flat()),
  mergeMap(({ length }) => length ? c.get('ghi') : of(undefined))
);

useful$.subscribe({
  next: () => { 
    // Completed...
  }
})

Nous a.get('abc') abord le résultat de a.get('abc') et utilisons mergeMap pour tester si abcdata.exist . S'il sort, nous retournons forkJoin(abcdatas.map(abcdata => b.get('def'))) simplement cela combinera un tableau d'observables générés à partir de la fonction map sur abcdatas

map(defdatas => defdatas.flat()), transformera le tableau en un seul tableau REMARQUE: flat () a été introduit dans ES2019

Ensuite, nous déstructurons la propriété length et si elle existe, nous retournons notre observable finale


1 commentaires

Appréciez votre réponse



1
votes

Je pense que ce que vous essayez de faire est ceci:

a.get("abc").pipe(
  mergeMap((abcdatas) => abcdatas.filter((abcdata) => abcdata.exist)), // let's create a stream with all those useful abcdata
  mergeMap(abcdata => b.get('def')), // and for each one of those we perform a b.get request
  toArray(), // once all the b.get requests have completed, emit a one value stream with an Array of those values values
  concatMap(useful => useful.length ? c.get('ghi') : EMPTY) // let's concat that result with the final request
)


1 commentaires

Appréciez votre réponse