Angular 使用rxjs.subscribe防止末日金字塔,并将.subscribe的数量角平化

Angular 使用rxjs.subscribe防止末日金字塔,并将.subscribe的数量角平化,angular,typescript,rxjs,observable,Angular,Typescript,Rxjs,Observable,我目前正在研究,但我也会在这里问这个问题,因为我发现这里的解释有时很精彩 好的,我有一个表单,根据用户输入打开一个模式窗口,我订阅模式关闭事件,并传回一些数据,在我调用/订阅服务方法检索一些数据后,我将使用这些数据,然后,当发生这种情况时,我再次执行相同的操作,并调用/订阅另一个服务方法来更新某个日期,然后在完成此操作后,我运行一个本地方法。我这里有3个嵌套的.subscribes const dialogRef = this.matDialog.open(ModalWindowComponen

我目前正在研究,但我也会在这里问这个问题,因为我发现这里的解释有时很精彩

好的,我有一个表单,根据用户输入打开一个模式窗口,我订阅模式关闭事件,并传回一些数据,在我调用/订阅服务方法检索一些数据后,我将使用这些数据,然后,当发生这种情况时,我再次执行相同的操作,并调用/订阅另一个服务方法来更新某个日期,然后在完成此操作后,我运行一个本地方法。我这里有3个嵌套的
.subscribe
s

const dialogRef = this.matDialog.open(ModalWindowComponent, {});
let userId = 4; // this is the real world is selected by the user
let userData = {}; // this is actually form data created by the user

// dialog is closed
dialogRef.afterClosed().subscribe((result) => {
  if (typeof result === 'string') {
     // subscribe to a service to get some data
     this.userService.getUser(userId).subscribe((user: any) => {
        // do something with the data
        let mergedObj = Object.assign({}, user, {newProperty: result});
          // subscribe to another service to update the data
          this.scbasService.updateUser(userId, mergedObj).subscribe(() => {
             this.doSomethingElse(userData); 
      });
    });
  }
});
我这里有一个“末日金字塔”。我记得在使用AngularJS和承诺时,我可以返回下一个服务并链接
.then()
s。我真的很想把我的代码扁平化,有什么想法吗

我怎么能在这里做同样的事情,这样我的代码就不会不断缩进


如果我没有很好地问自己或解释自己,请说出来,我会重新表述我的问题。

你可以这样做:

dialogRef
  .afterClosed()
  .filter(result => typeof result === 'string')
  .mergeMap(result => this.userService
    .getUser(userId)
    .mergeMap(user => {
      let mergedObj = Object.assign({}, user, { newProperty: result });
      return this.scbasService.updateUser(userId, mergedObj);
    })
  )
  .do(() => this.doSomethingElse(userData))
  .subscribe();
  • 使用
    过滤器
    ,以便只处理
    字符串
    结果
  • 使用
    mergeMap
    getUser
    updateUser
    调用组成一个内部可观察对象
  • 再次使用
    mergeMap
    将内部可见光合并到外部可见光中
  • 更新用户后,使用
    do
    执行操作
  • 然后调用
    subscribe
    。否则,什么也不会发生
需要记住的是,在
subscribe
调用中嵌套
subscribe
调用是一种反模式

如果需要,可以使用第一个
mergeMap
中的结果选择器进一步展平该属性:

dialogRef
  .afterClosed()
  .filter(result => typeof result === 'string')
  .mergeMap(
    result => this.userService.getUser(userId),
    (result, user) => Object.assign({}, user, { newProperty: result })
  )
  .mergeMap(
    userWithNewProperty => this.scbasService.updateUser(userId, userWithNewProperty)
  )
  .do(() => this.doSomethingElse(userData))
  .subscribe();

这太棒了-这是一个很好的答案,解释得很好,但是如果我想用非字符串的结果执行一个操作-例如,如果结果不是字符串,我会写入控制台?只需编写另一个可观察对象并订阅它:
dialogRef.afterClosed().filter(result=>typeof result!='string').do(result=>console.log(result)).subscribe()
。根据需要编写尽可能多的筛选器表达式。如果筛选器表达式相互排斥,则只有一个表达式可以执行某些操作。