3
votes

Attendez la fin de plusieurs requêtes http avant d'exécuter une fonction en angular

J'ai plusieurs publications http qui récupèrent les données JSON d'une base de données MySQL. Je veux qu'une fonction les écoute tous et exécute le code suivant une fois qu'ils ont tous renvoyé que les données ont été reçues.

J'ai essayé plusieurs variantes d'async avec await, mais la fonction ne semble pas attendez la fin de la publication HTTP.

J'ai un service de gestion des risques risk.service.ts pour obtenir le riskTable par exemple:

async getAllData(){
    let riskTable = await this.getRiskTable();
    let risks = await this.getAllRisks();

    console.log(riskTable); //This returns stuff
    console.log(risks);
    console.log(this.riskTable); //This returns undefined even though it was set in getRiskTable
  }

Activé mon tableau de bord j'appelle ce code:

getRiskTable():any {
    return this.riskService.getRiskTable().subscribe(
      (res: []) => {
        this.riskTable = res; // the value is correctly captured here
        return true;
      },
      (err) => {
        this.error = err;
      }
    );
  }

Et puis une fonction asynchrone qui exécute plusieurs de ces fonctions, en théorie, il est supposé attendre que toutes les fonctions soient terminées puis consigner la valeur . Mais pour une raison quelconque, la variable globale this.riskTable n'est pas définie dans cette fonction.

getRiskTable(): Observable<Risk[]> {
    return this.http.get(`${this.baseUrl}/getRiskTable`).pipe(
      map((res) => {
        this.riskTable = res['data'];
        return this.riskTable;
      }),
      catchError(this.handleError));
  }

S'il vous plaît tous les pointeurs - Je suis très nouveau dans angular et la complexité de cela m'a complètement perplexe. 2 jours et 100x variations pour que cela fonctionne Je perds lentement mes bananes!


2 commentaires

Vous pouvez penser à forkJoin , qui s'exécute tout en parallèle (si aucun ne dépend l'un de l'autre), et dans le rappel, vous pouvez faire tout ce que vous devez faire avec les données.


D'accord, j'ai jeté un coup d'œil rapide à found et à un exemple de forkJoin. Ils l'ont exécuté dans le service pour obtenir toutes les requêtes HTTP, puis renvoyer un résultat. J'ai plusieurs appels HTTP qui doivent rester modulaires. Je voudrais les appeler un par un à partir de divers composants, et c'est pour cette raison que je veux que le composant puisse accéder aux données d'un service et attendre qu'elles se terminent (en parallèle serait idéal mais je prendrai n'importe quoi À ce point).


3 Réponses :



5
votes

Tout d'abord, les mots-clés async / wait sont à utiliser avec des promesses, pas avec des Observable s. Vous pouvez donc convertir une observable en promesse en utilisant toPromise () ou vous pouvez utiliser rxjs ForkJoin . Vous devez également changer les méthodes pour renvoyer soit une observable, soit une promesse, vous ne pouvez pas faire grand-chose avec l'abonnement qui est ce que subscribe renvoie lorsque vous l'appelez et c'est ce que vous passez maintenant getRiskTable .

Un autre problème est que vous ne profitez pas du système de type, n'utilisez pas any partout car ces erreurs pourraient avoir été détectées au moment du transpile et maintenant, vous devez deviner pourquoi il échoue à l'exécution, ce qui est plus difficile.

import { forkJoin } from 'rxjs';
import { shareReplay } from 'rxjs/operators';

getRiskTable() : Observable<Risk[]> {
  const tableObservable = this.riskService.getRiskTable().pipe(shareReplay());
  tableObservable.subscribe((res) => this.riskTable = res, (err) => {this.error = err;});
  return tableObservable;
}

getAllData() {
  let riskTable = this.getRiskTable();
  let risks = this.getAllRisks(); // should also return some observable

  forkJoin(riskTable, risks).subscribe(_ => {
    // all observables have been completed
  });
}

Notez que j'ai également ajouté shareReplay qui garantit que plusieurs abonnements au même observable n'entraînent pas plusieurs appels vers votre point de terminaison API. Un résultat est partagé entre plusieurs abonnements à l'observable.


2 commentaires

Igor, il est 3 heures du matin ici. Je suis tellement heureux en ce moment, je vous ai écrit ce petit quelque chose: je suis designer Silly, visuel et Un peu pleurnichard Les choses sont devenues vraiment difficiles Dieu merci, Igor est venu Et a donné de l'amour au code @ _ @ !! 10/10 Je t'aime!


@BrendenEngelbrecht - heureux que cela fonctionne et j'espère que cela a encore du sens le matin (après avoir fermé les yeux) :)



0
votes

votre première fonction getRisk renvoie une observable pas une promesse, vous devez faire un .toPromise () pour convertir votre observable en promesse. votre deuxième fonction getRiskTable a abonné l'observable, ce qui est très incohérent par rapport à votre première, vous devriez faire la même chose que votre première fonction ne renvoie qu'une promesse, puis votre attente asynchrone devrait fonctionner.

ou vous pouvez utiliser forkjoin (obs1, obs2), dépend de votre intérêt, mais restez cohérent.


0 commentaires