Angular 带有 HttpClient 的异步函数
Angular Asynchronous function with HttpClient
好吧,我整天都在为这件事绞尽脑汁。本质上,我有一个按钮可以让学生退出 class。那部分很简单。但是,它还应该检查数据库中的等候名单 class,如果有的话,请登记下一个排队的人。
所以在我看来,操作顺序是...
- 存储课程 ID 以备将来使用
- 从 class (HTTP #1)
中撤回学生 A
- 获取 class 的等候名单(这是我使用保存的 ID 的地方)(HTTP #2)
- 制作响应数组
- 如果数组长度为0,结束
- 如果数组长度大于0,继续
- 从数组[0]创建学生 B 对象
- 将学生 B 注册到 class (HTTP #3)
- 从候补名单中删除学生 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的逻辑是一样的。这就是为什么您无法将您的代码与您的方法同步的原因。看看我的第一个例子,然后从那个开始。
好吧,我整天都在为这件事绞尽脑汁。本质上,我有一个按钮可以让学生退出 class。那部分很简单。但是,它还应该检查数据库中的等候名单 class,如果有的话,请登记下一个排队的人。
所以在我看来,操作顺序是...
- 存储课程 ID 以备将来使用
- 从 class (HTTP #1) 中撤回学生 A
- 获取 class 的等候名单(这是我使用保存的 ID 的地方)(HTTP #2)
- 制作响应数组
- 如果数组长度为0,结束
- 如果数组长度大于0,继续
- 从数组[0]创建学生 B 对象
- 将学生 B 注册到 class (HTTP #3)
- 从候补名单中删除学生 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的逻辑是一样的。这就是为什么您无法将您的代码与您的方法同步的原因。看看我的第一个例子,然后从那个开始。