我遇到了一个有问题的方法,我需要执行所有嵌套方法(包括 subscirbe),然后才设置 isLoading = false,但是在执行所有嵌套逻辑之前,isLoading 标志设置为 false。
你有什么想法可以告诉我吗? 我试着用示意性的方式编写代码,而不深入细节
getData() {
isLoading = true;
this.someSevice.getSomeData().subscribe(response => {
...
getUserData(response);
isLoading = false;
},
error => {
isLoading = false;
this.errors = error;
});
}
getUserData(data: any) {
...
this.someSevice.getUserData().subscribe(response => {
...
getMetadata(response);
});
}
getMetadata(data: any) {
...
this.someSevice.getMetadata().subscribe(response => {
...
});
}
答案 0 :(得分:1)
您可以使用管道通过 mergeMap
运算符按顺序执行您的请求。如果您有顺序请求,其中每个请求都需要前一个请求的响应,那么这是一种常见模式。 mergeMap
至少需要一个参数,该参数必须是返回 Observable
(或 Promise
)的函数。所以我也因此修改了 getUserData
和 getMetadata
。
getData() {
isLoading = true;
this.someSevice.getSomeData().pipe(
mergeMap(getUserData),
mergeMap(getMetadata),
)
.subscribe(
response => {
isLoading = false;
},
error => {
isLoading = false;
this.errors = error;
},
);
}
getUserData(data: any) {
...
return this.someSevice.getUserData();
}
getMetadata(data: any) {
...
return this.someSevice.getMetadata();
}
答案 1 :(得分:1)
您可以通过使用“Higher Order Mapping Operators”(mergeMap
、concatMap
、switchMap
、exhaustMap
)来避免嵌套订阅。这些特殊的操作符将为您订阅一个内部可观察对象(并管理取消订阅)并传播来自它的排放。
在您的情况下,让我们使用 switchMap
:
private getData() {
this.isLoading = true;
this.service.getSomeData().pipe(
switchMap(data => this.service.getUserData(data.userId)),
switchMap(user => this.service.getMetaData(user.id)),
tap(() => this.isLoading = false) // <--- at this point, all calls are done
);
}
上面的代码定义了一个以调用getSomeData()
开始的流;第一个 switchMap
接收 getSomeData()
发出的值并将其映射到一个新的 observable getUserData()
,switchMap
将在内部订阅并将输出传递给下一个 {{ 1}},反过来做同样的事情。
到 switchMap
运算符被击中时,已收到来自所有 3 个先前调用的所有响应。
如果我们想要建立一个依赖于先前调用的响应的数据响应,我们需要一种方法来访问来自那些先前调用的数据。
这可以通过在 tap
中添加一个 .pipe()
来实现,基本上像这样嵌套它们:
switchMap
查看这个完全有效的 StackBlitz 示例。我相信你可以修改它以满足你的需要:-)