Angular 带有 HttpClient 的异步函数

Angular Asynchronous function with HttpClient

好吧,我整天都在为这件事绞尽脑汁。本质上,我有一个按钮可以让学生退出 class。那部分很简单。但是,它还应该检查数据库中的等候名单 class,如果有的话,请登记下一个排队的人。

所以在我看来,操作顺序是...

  1. 存储课程 ID 以备将来使用
  2. 从 class (HTTP #1)
  3. 中撤回学生 A
  4. 获取 class 的等候名单(这是我使用保存的 ID 的地方)(HTTP #2)
  5. 制作响应数组
  6. 如果数组长度为0,结束
  7. 如果数组长度大于0,继续
  8. 从数组[0]创建学生 B 对象
  9. 将学生 B 注册到 class (HTTP #3)
  10. 从候补名单中删除学生 B。 (HTTP #4)

我可以将代码写得足够好以进行编译,并且每个单独的部分都可以正常工作。但总的来说,我的同步函数变成了异步函数,无法按预期工作。罪魁祸首是第 3 步和第 4 步。虽然第 3 步仍然未决,但 JS 移动到第 4 步并且代码 stops 因为显然数组是空的。

onWithdrawClass(row:any){
    let courseId = row.courseId;

    //display a confirmation message
    if(confirm("Are you sure you want to withdraw from this course?\n \nYou may not be able to get your seat back if you do.")){
      
      //use the api service to perform the withdraw and refresh the list
      this.api.deleteWithdraw(row.id).subscribe(res=>{
        alert("You have been successfully withdrawn from this course.");
          let ref = document.getElementById('refresh');
          ref?.click();
      },
      err=>{
        alert("Something went wrong with withdrawal.\nTry refreshing the page to see if it worked.");
      })

      //get waiting list for that course
      this.api.getWaitlistByCourseId(courseId).subscribe(res=>{
        this.courseById = res;
      })

      //do this if there is someone waiting for that class
      if(this.courseById.length > 0){
        //create student object
        this.studentObj.id = this.courseById[0].id;
        this.studentObj.courseId = this.courseById[0].courseId;
        this.studentObj.courseName = this.courseById[0].courseName;
        this.studentObj.courseInstructor = this.courseById[0].courseInstructor;
        this.studentObj.studentFirstName = this.courseById[0].studentFirstName;
        this.studentObj.studentLastName = this.courseById[0].studentLastName;
        this.studentObj.studentEmail = this.courseById[0].studentEmail;
        
        //enroll that student from wait list into course
        this.api.enrollStudent(this.studentObj).subscribe(res=>{
          console.log("waiting list student enrolled.")
        },
        err=>{
          console.log("error with enrolling waiting list student.")
        })
        //remove that student from wait list
        this.api.deleteFromWaitingList(this.courseById[0].id).subscribe(res=>{
          console.log("student removed from waiting list")
        },
        err=>{
          console.log("error with deleting student from waiting list")
        })
      }
    }
  }

和 api 服务 ts

enrollStudent(data:any){
        return this.httpClient.post<any>("ENROLL-URL", data)
        .pipe(map((res:any)=>{
          return res;
        }))
      }

deleteWithdraw(id:number){
        return this.httpClient.put<any>("WITHDRAW-URL", id)
        .pipe(map((res:any)=>{
          return res;
        }))
      }

getWaitlistByCourseId(courseId:string){
        return this.httpClient.post<any>("WAITLIST-URL", courseId)
        .pipe(map((res:any)=>{
          return res;
        }))
      }

deleteFromWaitingList(id:number){
        return this.httpClient.put<any>("WAITLIST-DELETE-URL", id)
        .pipe(map((res:any)=>{
          return res;
        }))
      }

我认为使用 async/await 是“正确”执行此操作的最佳方式,但我不知道如何从 http 调用中获得承诺或等待它。

(ps。如果你正在查看我的 httpClient 调用并说“你有 .put 删除和 .post 获取”我知道。这很奇怪。那是这是让它与 Cosmos DB 一起工作的唯一方法。它们都可以工作,这不是问题,我保证。)

已解决:

感谢munleashed 的帮助!他的回答并没有完全解决我的问题,但这正是让齿轮在我脑海中转动的原因。对于在这里寻找解决方案的任何人,这就是我的结尾......

courseById: any[] = [];

async doTheThingZhuLi(courseId: undefined){
    this.response = await this.http.post<any>("WAITLIST-URL", courseId)
    .pipe(map((res:any)=>{
      this.courseById = res;
    })).toPromise();
  }

onClickWithdraw(row:any){
    if(confirm("Are you sure you want to withdraw from this course?")){
      this.doTheThingZhuLi(row.courseId).then(res=>{
        this.moveFromWaitList(); //this handles steps 6 - 9
      }
      ).finally(() =>{
        this.actuallyWithdrawTheStudent(row.id);
      });
    }
  }

我不确定我是否完全理解你想要做什么,但我发现你在同步 api 调用时遇到了问题。 如果您想等待一个 API 调用完成以便调用另一个 API 调用,您必须使用一些 RXJS 管道运算符。 例如:

const api1 = this.service.getApi1();
const api2 = this.service.getApi2();

api1.pipe(switchMap(api1Result => {
// Here you can use result of api1 call

return ap2;
}).subscribe(api2Result => {
// Here you can use result of api2Call
});

基本上,机制与 Promises 的工作方式类似:

console.log(1);
const promise = new Promise((res) => {res()});
promise.then(res => console.log('3'));
console.log(4);

// It will print 1 4 3 (3 at the end because its an asyns operation)

Observables和RXJS的逻辑是一样的。这就是为什么您无法将您的代码与您的方法同步的原因。看看我的第一个例子,然后从那个开始。