为什么 RxJs 在链式 http 调用完成之前完成执行?
Why does RxJs finalize execute before chained http calls are complete?
Angular 11 个站点。我已经搜索了所有地方,但我仍在为这似乎是一个很常见的场景而苦苦挣扎。
目标: 执行一个 http 调用以检索项目列表,然后执行另一个 http 调用以检索第一个项目的详细信息。两次调用完成后(无论成功还是失败),隐藏组件的整体等待指示器。
这是一个高度简化的版本,没有空检查和错误处理:
ngOnInit(): void {
this.getPackages();
}
private getPackages() {
this._packageSubscription = this.packageService.getPackages()
.pipe(
finalize(() => {
console.log('getPackages finalize');
this.loadingPackages = false; //hide wait indicator: happens BEFORE getPackageDetails is finished
})
)
.subscribe(
packages => {
this.packageOptions = packages;
this.selectedPackage = packages[0];
this.loadSelectedPackage();
}
);
}
public loadSelectedPackage() {
this._packageDetailsSubscription = this.packageService.getPackageDetails(this.selectedPackage!.Id)
.pipe(
finalize(() => {
console.log('getPackageDetails finalize');
})
)
.subscribe(
packageDetails => {
this.packageDetails = packageDetails;
}
);
}
执行时,控制台显示:
getPackages finalize
getPackageDetails finalize
我希望相反。
我知道我可以添加我的代码来为 getPackageDetails()
停用内部 finalize()
中的等待指示器,但是这有一些问题:
- 这似乎是错误的。为什么我不知道链在外层何时完成?
- 那只能涵盖一切都成功的情况。当第一次调用失败时,我必须在某处添加第二行代码以隐藏等待指示器。
loadSelectedPackage()
可以在用户操作更改所选包后再次调用,因此处理仅与初始加载相关的内容更没有意义。
那么为什么我的外部 finalize()
不等到链完成?或者我还能如何知道链何时完成?
这实际上是您得到的正确结果。您编写代码的方式没有链条。这两个订阅是相互独立的,通过从 subscribe
中调用 this.loadSelectedPackage();
你不会连接它们或类似的东西。
您实际上应该使用一些地图运算符并且只订阅一次。在你的情况下,我认为 concatMap()
是合适的。让 getPackages()
发生,将值分配给对象属性,然后连接新的可观察对象以获取详细信息。
private getPackages() {
this._packageSubscription = this.packageService.getPackages()
.pipe(
concatMap(packages => {
this.packageOptions = packages;
this.selectedPackage = packages[0];
return this.packageService.getDetails(this.selectedPackage!.Id);
}),
finalize(() => {
console.log('getPackages finalize');
this.loadingPackages = false;
})
)
.subscribe(packageDetails => {
this.packageDetails = packageDetails;
});
}
这应该可以解决问题。
Angular 11 个站点。我已经搜索了所有地方,但我仍在为这似乎是一个很常见的场景而苦苦挣扎。
目标: 执行一个 http 调用以检索项目列表,然后执行另一个 http 调用以检索第一个项目的详细信息。两次调用完成后(无论成功还是失败),隐藏组件的整体等待指示器。
这是一个高度简化的版本,没有空检查和错误处理:
ngOnInit(): void {
this.getPackages();
}
private getPackages() {
this._packageSubscription = this.packageService.getPackages()
.pipe(
finalize(() => {
console.log('getPackages finalize');
this.loadingPackages = false; //hide wait indicator: happens BEFORE getPackageDetails is finished
})
)
.subscribe(
packages => {
this.packageOptions = packages;
this.selectedPackage = packages[0];
this.loadSelectedPackage();
}
);
}
public loadSelectedPackage() {
this._packageDetailsSubscription = this.packageService.getPackageDetails(this.selectedPackage!.Id)
.pipe(
finalize(() => {
console.log('getPackageDetails finalize');
})
)
.subscribe(
packageDetails => {
this.packageDetails = packageDetails;
}
);
}
执行时,控制台显示:
getPackages finalize
getPackageDetails finalize
我希望相反。
我知道我可以添加我的代码来为 getPackageDetails()
停用内部 finalize()
中的等待指示器,但是这有一些问题:
- 这似乎是错误的。为什么我不知道链在外层何时完成?
- 那只能涵盖一切都成功的情况。当第一次调用失败时,我必须在某处添加第二行代码以隐藏等待指示器。
loadSelectedPackage()
可以在用户操作更改所选包后再次调用,因此处理仅与初始加载相关的内容更没有意义。
那么为什么我的外部 finalize()
不等到链完成?或者我还能如何知道链何时完成?
这实际上是您得到的正确结果。您编写代码的方式没有链条。这两个订阅是相互独立的,通过从 subscribe
中调用 this.loadSelectedPackage();
你不会连接它们或类似的东西。
您实际上应该使用一些地图运算符并且只订阅一次。在你的情况下,我认为 concatMap()
是合适的。让 getPackages()
发生,将值分配给对象属性,然后连接新的可观察对象以获取详细信息。
private getPackages() {
this._packageSubscription = this.packageService.getPackages()
.pipe(
concatMap(packages => {
this.packageOptions = packages;
this.selectedPackage = packages[0];
return this.packageService.getDetails(this.selectedPackage!.Id);
}),
finalize(() => {
console.log('getPackages finalize');
this.loadingPackages = false;
})
)
.subscribe(packageDetails => {
this.packageDetails = packageDetails;
});
}
这应该可以解决问题。