Angular 如何使用switchMap代替嵌套订阅

Angular 如何使用switchMap代替嵌套订阅,angular,rxjs,angular-material,angular2-observables,Angular,Rxjs,Angular Material,Angular2 Observables,很长时间的潜伏者。没想到我真的会发帖,但我真的被这篇文章困住了 我仍在学习可观察性,所以如果有一个简单的解决方案,我不会感到惊讶。基本上我现在有四个嵌套订阅,第二个subscribe()中有一个fourEach。我使用switchMap看到了很多答案,但我找不到一个也有for循环的答案。我知道我可能应该使用嵌套订阅,但我不知道如何使用forEach 这是嵌套订阅的工作代码: dialogRef.afterClosed().subscribe(result => { if(result)

很长时间的潜伏者。没想到我真的会发帖,但我真的被这篇文章困住了

我仍在学习可观察性,所以如果有一个简单的解决方案,我不会感到惊讶。基本上我现在有四个嵌套订阅,第二个subscribe()中有一个fourEach。我使用switchMap看到了很多答案,但我找不到一个也有for循环的答案。我知道我可能应该使用嵌套订阅,但我不知道如何使用forEach

这是嵌套订阅的工作代码:

dialogRef.afterClosed().subscribe(result => {
  if(result) {
    this.createLikertResponseGroup(result.likertResponseGroup)
      .subscribe(likertResponseGroupJSON => {

        result.likertResponse.controls.likertResponseFormArray.controls.forEach((element) => {
          let characteristic = element.controls.characteristic;
          this.newResponseGroupId = likertResponseGroupJSON.LikertResponseGroup.id;

          this.createLikertResponse(element, this.newResponseGroupId)
            .subscribe(likertResponseJSON => {

              if (characteristic) {
                let responseId = likertResponseJSON.LikertResponse.id;

                this.createCharacteristic(characteristic, this.newResponseGroupId, responseId)
                  .subscribe(characteristicJSON => {
                    this.newCharacteristicId = characteristicJSON.Characteristic.id;
                  });
              }
            });
        });
      })
  }
});
我现在所拥有的一切都起作用了。所以我的问题是,我这样做是否值得改变?如果是的话,我会怎么做

我还没走多远,但我尝试使用switchMap时如下所示:

dialogRef.afterClosed().pipe(
  filter(result => result != null),
  switchMap(result => 
    from(result.likertResponse.controls.likertResponseFormArray.controls).pipe(
      // not sure what to do after this (or if I'm even doing it right)
    )
  ),
);
mergeMap
而不是嵌套的
subscribe
mergeMap执行嵌套订阅的所有操作,但它还允许您在发出订阅值时继续逻辑


快速靠边站:

在订阅的observable发出一次并完成(如http请求)的情况下,
switchMap
mergeMap
产生相同的输出<在这些情况下,通常建议使用代码>开关映射而不是
合并映射
。原因包括调试内存泄漏、性能不佳以及其他开发人员的期望

为了简单起见,我在这里忽略了这一点,在所有情况下都使用了
mergeMap


您可以通过嵌套
mergeMap
和/或嵌套
subscriptions
来隐藏一些复杂性,因为您可以依靠函数闭包在管道的早期设置和记住值

这也可能会导致接下来的混乱。众所周知,在JS中调试深度嵌套的函数非常困难,因此映射到中间对象以保存下一步所需的值(而不是通过函数闭包嵌套和获取中间值)的额外工作是值得的

它也稍微快一些,因为运行时不需要在调用堆栈中查找变量(但同样,您应该这样做,因为它更干净、可维护和可扩展,而不是为了尽早优化)

以下是使用mergeMap和包含Intermate值的对象临时重新编写的代码:

dialogRef.afterClosed()管道(
过滤器(结果=>result),//
这个.createLikerResponseGroup(result.likerResponseGroup).pipe(
映射(likertResponseGroupJSON=>({result,likertResponseGroupJSON}))
)
),
mergeMap({result,likertResponseGroupJSON})=>merge(
…result.likerresponse.controls.likerresponseformarray.controls.map(
element=>this.createLikerResponse(
元素,
likertResponseGroupJSON.LikertResponseGroup.id
).烟斗(
映射(likertResponseJSON=>({
像杰森一样,
特征:元素。控制。特征,
newResponseGroupId:likerResponseGroupJSON.likerResponseGroupId
}))
)
)
)),
过滤器(({characteristic})=>characteristic)//只允许使用“Truthy”特征
合并映射({likertResponseJSON,characteristic,newResponseGroupId})=>
这是我的特点(
特征
newResponseGroupId,
likertResponseJSON.LikertResponse.id
).烟斗(
映射(characteristicJSON=>({
newCharacteristicId:characteristicJSON.Characteristic.id,
newResponseGroupId
}))
)
)
).subscribe({newCharacteristicId,newResponseGroupId})=>{
this.newResponseGroupId=newResponseGroupId;
this.newCharacteristicId=newCharacteristicId;
});
merge
/
forkJoin
/
concat
而不是
forEach(stream.subscribe())
您会在上面的代码中注意到,当需要重新编写forEach循环时,我使用了
merge
Array\map
的组合,而不是
Array\forEach

merge
相当于
forEach(stream.subscribe())
,但其他方法可以改变行为,甚至可以提高性能,或者让您直观地合成更复杂的流

这里,第2行和第3行具有相同的输出。然而,第二种方法很容易用更多的RxJS操作符进行扩展

1。常量数组流=[s1,s2,s3,s4];
2.forEach(s=>s.subscribe(console.log));
3.合并(…arrayOfStreams).subscribe(console.log);
扩展:

arrayOfStreams.forEach(s=>s.subscribe(值=>{
if(this.isGoodValue(value)){
console.log(value.append(“end”))
}
}));
合并(…arrayOfStreams).pipe(
过滤器(此.isGoodValue),
映射(value=>value.append(“end”))
).subscribe(console.log);

使用开关映射的想法是,第一个“可观察部分”应该返回一个新的可观察部分,而不是订阅一个新的可观察部分
switchMap
将在它们之间进行粘合,基本上将
subscribe
替换为“完成第一个订阅并将其切换到另一个”。现在,在第一个案例中,有一个
if
和两个案例。因此,如果您想使用switchmap,您必须在这两种情况下都返回一个可观测值。如果不想执行任何操作,可以返回
Observable.empty
。在您的正常情况下,返回
this.createLikerResponseGroup(result.likerResponseGroup)
作为一个辅助建议,为了实验观察值和学习,您可以使用StackBlitz。或者直接转到
https://rxjs.dev/
打开控制台,rxjs加载在那里。只需替换实际的API调用
dialogRef.afterClosed()
返回一些您硬编码的虚拟可观察对象(可能带有一些“setTimeout”来模拟异步性),以及许多
console.log
来可视化程序流。我建议您阅读本文:swi