【问题标题】:Preventing a Pyramid of Doom using rxjs .subscribe with Angular - flattening the number of .subscribes使用 rxjs .subscribe 和 Angular 来防止末日金字塔 - 扁平化 .subscribe 的数量
【发布时间】:2018-03-30 00:54:55
【问题描述】:

我目前正在调查RxJS's .merge,但我也会在这里问这个问题,因为我有时会发现这里的解释很精彩。

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

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 并使用 promises 时,我可以返回下一个服务并链接.then()s。我真的很想扁平化我的代码,有什么想法吗?

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

如果我没有很好地提问或解释自己,请说出来,我会改写我的问题。

【问题讨论】:

    标签: angular typescript rxjs observable


    【解决方案1】:

    你可以这样做:

    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();
    
    • 使用filter,以便只处理string 结果。
    • 使用mergeMapgetUserupdateUser 调用组成一个内部可观察对象。
    • 再次使用 mergeMap 将内部 observable 合并到外部 observable 中。
    • 用户更新后使用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();
    

    【讨论】:

    • 这太棒了 - 一个很好的答案,很好地解释了但是如果我想执行一个结果不是字符串的操作 - 例如,如果结果不是我写入控制台的字符串?
    • 只需编写另一个 observable 并订阅它:dialogRef.afterClosed().filter(result => typeof result !== 'string').do(result => console.log(result)).subscribe()。根据需要编写尽可能多的内容。如果过滤器表达式是互斥的,那么只有一个会做某事。
    猜你喜欢
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多