2
votes

utiliser switchMap pour désabonner la précédente requête http et ne prendre que la dernière

Je suis actuellement confronté à un problème, où une première recherche peut prendre 5 secondes et une seconde qui prend 2 secondes, le problème est que la première recherche qui prend plus de temps "effacera" les résultats de la requête qui a été effectuée après, car les appels se terminent après.

J'ai essayé de lire sur

switchMap

dans rxJs et j'ai essayé de l'utiliser, mais d'après ce que j'essaye, il ne se désabonne pas de la demande précédente et efface le résultat.

Il y a probablement quelque chose que je fais mal ici, mais je ne peux pas indiquer exactement quel est le problème.

La fusion a 3 sources de changement dans le résultat (pagination, tri ou nouveaux critères de recherche), et le call to sendSearchCriteria renvoie les données utilisées.

sendSearchCriteria renvoie un Observable

y a-t-il quelque chose qui me vient à l'esprit, que je fais mal?

Merci pour votre aide,

private loadDogsResults = (filtersInformation: FilterSearchCriteria) => {
    merge(this.sort.sortChange, this.paginator.page, of(filtersInformation))
      .pipe(
        distinctUntilChanged(),
        tap(() => (this.isLoading = true)),
        switchMap(() => this.sendSearchCriteria(filtersInformation)),
        //mergeMap(() => this.sendSearchCriteria(filtersInformation)),
        map(data => this.formatResults(data)),
        finalize(() => (this.isLoading = false)),
        catchError(error => this.handleError(error)),
        takeUntil(this._onDestroy$)
      )
      .subscribe((result: any[]) => {
        if (result.length > 0) {
          this.setDisplayedColumns(result[0]);
        }
        this.isLoading = false;
      });
  }


11 commentaires

Ce que vous décrivez est exactement le cas d’utilisation de switchMap, il annule les requêtes en cours qui sont anciennes et même si ce n’est pas le cas, il ignore leurs résultats.


oui mais c'est le problème, cela ne fonctionne pas comme je le souhaiterais, la requête n'est pas annulée et les résultats sont pris, même avec l'utilisation de switchMap commenté: /


Essayez de créer un exemple minimal reproductible sur stackblitz.io - à partir d'un test rapide avec les éléments http et switchMap d'angular semblent fonctionne normalement. Votre princesse est dans un autre château, quelque chose d'autre ne va pas avec votre code.


Notez que mergeMap (que vous avez ici au lieu de switchMap) ne fonctionnera absolument pas pour cela et n'annulera pas l'événement - c'est par conception.


oui, en décommentant switchMap, je commente le mergeMap, ce qui n'aide pas :(


un collègue m'a envoyé un stackblitz.io qui fonctionne bien pour le cas d'utilisation de switchMap, mais malheureusement cela ne m'aide pas à voir plus clairement ce qui ne va pas dans mon code stackblitz.com/edit/rxjs-ui3che


Je ne peux vraiment rien vous aider si le stackblitz est un exemple fonctionnel - je sais déjà que switchMap fonctionne dans stackblitz:] Désolé et que les dieux du débogage soient en votre faveur.


merci :) J'espère que je parviendrai à le résoudre!


Que renvoie sendSearchCriteria ou comment crée-t-il l'appel à distance? Afin de faire fonctionner switchMap dans les besoins de renvoyer un abonnement, chat peut être désabonné.


@ Dinosan0908 Comment est appelé loadDogsResults ? Est-il appelé une seule fois ou l'appelez-vous plusieurs fois (par exemple, chaque fois que filtersInformation change)?


merci les gars, solution trouvée grâce à toutes les idées!


3 Réponses :


2
votes

Quel événement déclenche la recherche ? Cet événement doit être la source de votre Observable , qui sera "canalisé" avec l'opérateur switchMap .

Comme je peux le voir ici, si vous appelez loadDogsResults () pour chaque événement, cela ne fonctionnera pas car vous créez un nouvel Observable à chaque fois. of (filtersInformation) est un observable qui émet la valeur filtersInformation UNE FOIS lorsque l'observable est abonné, je ne pense pas que ce soit le comportement attendu.


1 commentaires

Merci, en effet ce n'était pas le cas, cela a conduit à la solution que j'ai postée :) merci beaucoup!



1
votes

Vous effectuez une fusion sur 3 observables distincts, ce qui vous permettra d'entrer dans le tube à 3 reprises et de lancer 3 appels distincts à sendSearchCriteria. Si vous voulez appeler sortChange et page, obtenir les résultats des deux puis appeler sendSearchCriteria, vous pouvez ...

private loadDogsResults = (filtersInformation: FilterSearchCriteria) => {
    forkJoin(this.sort.sortChange, this.paginator.page)
      .pipe(
        distinctUntilChanged(),
        tap(() => (this.isLoading = true)),
        switchMap(() => this.sendSearchCriteria(filtersInformation)),
        //mergeMap(() => this.sendSearchCriteria(filtersInformation)),
        map(data => this.formatResults(data)),
        finalize(() => (this.isLoading = false)),
        catchError(error => this.handleError(error)),
        takeUntil(this._onDestroy$)
      )
      .subscribe((result: any[]) => {
        if (result.length > 0) {
          this.setDisplayedColumns(result[0]);
        }
        this.isLoading = false;
      });
  }

Cependant, gardez à l'esprit que dans votre abonnement, vous n'aurez accès qu'à à la réponse de sendSearchCriteria.


1 commentaires

Je vous remercie ! Le problème était plus dû à l'initialisation mais en effet la fusion était un problème, merci pour le lead, cfr: solution postée!



0
votes

Un collègue m'a aidé à trouver le problème :) nous avons essayé forkJoin, combineLatest et plusieurs options, mais le plus gros problème était l'initialisation / l'abonnement effectué d'une manière étrange.

Nous avons maintenant créé un searchTriggerSubject et ajouté ces lignes

< pre> XXX

les filtres venaient d'un service, c'est donc ce que nous avons fait pour éviter le problème.

Une refactorisation était nécessaire

Merci beaucoup à tous pour les différents prospects, avoir plusieurs sujets facilite les choses


0 commentaires