3
votes

rxjs équivalent à l'arrêt d'une fonction asynchrone en utilisant 'return';

Je veux implémenter quelque chose de similaire ci-dessous (ils sont faciles si vous utilisez des promesses)

doSomething(sID){
  let student;
  let teacher;
  service.getStudent(sID).pipe(
      switchMap(studentR=>{
        student = studentR;
        return service.getTeacher(student.TeacherID);
      }),
      switchMap(teacherR=>{
        teacher = teacherR;
        if(!teacher.Active){
            return of(null);
        }else{
            return service.teacherSomething(teacher);
        }
      }),
      swicthMap(teacherSomethingResponse=>{
          if(teacherSomethingResponse==null){
              return of(null);
          }else{
            return service.studentSomething(student);
          }
      })
  }).subscribe();

}

Je n'ai aucune idée de comment faire cela si j'utilise des observables au lieu de promesses celui que j'ai essayé jusqu'à présent

async doSomething(sID){
 let student = await service.getStudent(sID);
 let teacher = await service.getTeacher(student.TeacherID);
 if(!teacher.Active){
   return;
 }

 await service.teacherSomething(teacher);
 await service.studentSomething(student);
}

comme vous pouvez le voir, ma version rxjs semble TROP LONGUE par rapport à la version promise et j'ai l'impression de ne pas le faire de la bonne façon.


0 commentaires

3 Réponses :


1
votes

async / await a été développé principalement comme une fonctionnalité de lisibilité, il est donc naturel d'être assez succinct visuellement. En utilisant l'ancienne syntaxe Promise , vous obtiendrez une fonction beaucoup plus longue. Donc, en bref, vous utilisez très bien les observables, et c'est plus long en raison des différences de syntaxe attendues.


1 commentaires

mais que faire si j'ai besoin de faire quelque chose comme si teacherSomethingResponse est nul, alors faire un appel alternatif? ce qui signifie que ma chaîne est fausse car je ne devrais pas entrer dans la ligne qui mène au service.teacherSomething aussi longtemps que teacher.Active == false



3
votes

Voici comment vous pouvez convertir votre code actuel en style Rx. takeWhile complétera votre observable si la condition n'est pas remplie

function doSomething(sID) {
  return from(service.getStudent(sID)).pipe(
    switchMap(student =>
      service.getTeacher(student.TeacherID).pipe(
        takeWhile(teacher => teacher.Active),
        switchMap(teacher => service.teacherSomething(teacher).pipe(takeWhile(res => res))),
        switchMap(() => service.studentSomething(student))
      )
    ))
}


0 commentaires

0
votes

Dans votre cas, vous pouvez éviter de sauvegarder les valeurs de l'enseignant et de l'élève, car les propager sur le pipeline, je pense, est assez correct dans votre cas d'utilisation.

Pour cela, après avoir demandé à l'enseignant, je mappe la réponse et renvoie les données élève et enseignant sous forme de tuple .

Si le L'enseignant n'est pas actif, renvoyer une erreur pourrait être une solution élégante si vous voulez faire quelque chose par erreur, sinon vous pouvez également renvoyer VIDE , c'est un observable qui fait ne pas émettre et se termine simplement.

Donc, c'est ma solution, étant donné que les requêtes 'teacherSomething' et 'studentSomething' peuvent être faites en parallèle puisque cela ne semble pas dépendre de les uns aux autres

doSomething(sID){
  service.getStudent(sID).pipe(
      switchMap(studentR =>
        service.getTeacher(student.TeacherID).pipe(map((teacherR) => [studentR, teacherR]))),
      switchMap(([studentR, teacherR]) => {
        if(!teacherR.Active){
            throw new Error('Teacher is not active'); // or return EMPTY
        }
        // Both request teacher something and student something done in 'serie'
        return service.teacherSomething(teacher)
            .pipe(switchMap((teacherSomethingR) => 
                service.studentSomething(student)
                .pipe(map((studentSomethingR) => [teacherSomethingR, studentSomethingR]))
            ))
      })
  ).subscribe(
    ([teacherSomethingR, studentSomethingR]) => {/* do something with responses */},
    (error) => { /* Do something if teacher not active, or some request has been error...*/ }
  );
}

Si les requêtes ne peuvent pas être effectuées en parallèle , je ferais exactement la même chose que précédemment (switchMap) et je retournerais le tuple de réponses afin de faire quelque chose si nécessaire. Si cela n'est pas nécessaire, vous pouvez éviter cette dernière étape:

doSomething(sID){
    service.getStudent(sID).pipe(
        switchMap(studentR =>
          service.getTeacher(student.TeacherID).pipe(map((teacherR) => [studentR, teacherR]))),
        switchMap(([studentR, teacherR]) => {
          if(!teacherR.Active){
              throw new Error('Teacher is not active'); // or return EMPTY
          }
          // I think this two request may have been done in parallel, if so, this is correct.
          return zip(service.teacherSomething(teacher), service.studentSomething(student));
        })
    ).subscribe(
      ([teacherSomethingR, studentSomethingR]) => {/* do something with responses */},
      (error) => { /* Do something if teacher not active, or some request has been error...*/ }
    );
  }

J'espère que cela vous aidera!


0 commentaires