rxjs相当于使用'return'停止异步功能;

时间:2019-01-14 14:16:20

标签: javascript typescript rxjs

我想在下面实现类似的功能(如果使用诺言,这很容易)

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);
}

如果我使用可观察变量而不是promise,我不知道如何执行此操作,但这是我到目前为止尝试过的

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();

}

如您所见,与promise版本相比,我的rxjs版本似乎太长了,我觉得我做的方式不正确。

3 个答案:

答案 0 :(得分:3)

这是将当前代码转换为Rx样式的方法。如果不满足条件,takeWhile将完成您的可观察性

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))
      )
    ))
}

答案 1 :(得分:1)

async/await主要是为了提高可读性而开发的,因此视觉上很简洁是很自然的。 使用旧式Promise语法,您将获得更长的功能。 因此,简而言之-您可以很好地使用observables,并且由于预期的语法差异,它的使用时间更长。

答案 2 :(得分:0)

在您的情况下,您可以避免保存教师和学生的价值,因为我认为在用例中将其传播到管道中是正确的。

为此,在请求老师之后,我将映射,并将学生和老师的数据作为元组返回。

如果老师没有上课,抛出错误可能是一个很好的解决方案,如果您想对错误做一些事情,或者您还返回空,那是可观察到的,不会发出,只是完成。

所以,这是我的解决方案,考虑到请求'teacherSomething'和'studentSomething'可以并行完成,因为它们似乎并不相互依赖

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...*/ }
    );
  }

如果请求无法并行完成,我将做与之前(switchMap)相同的操作,并返回响应的元组,以便在需要时执行某些操作。如果不需要,您可以避免最后一步:

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...*/ }
  );
}

希望这会有所帮助!