【问题标题】:RxJs operators avoid multiple subscriptions, with loopRxJs 操作符避免多次订阅,有循环
【发布时间】:2019-11-28 08:05:56
【问题描述】:

我正在为 Angular 应用程序编写导航组件。我有以下代码。我想避免多重订阅反模式。我正在为 RxJs 语法和走哪条路(forkJoin、mergeMap 等)而苦苦挣扎。

我如何重构这些,以删除订阅中的订阅。

这是我所拥有的,目前有效,但在订阅中有订阅:

@Component({
  selector: 'ehrcc-nav',
  templateUrl: './nav.component.html',
  styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {

  applicationName: string = 'AppName';
  userDisplayName: string = '';
  isAuthorizedUser: boolean = false;
  isAdminUser: boolean = false;

  groupsList: MemberGroup[] = [];

  constructor(private userService:UserService,
    private auditService: UserAuditService,
    private router: Router) { }

  ngOnInit() {

    this.getDisplayName();

    this.userService.getGroupMembershipsForUser().subscribe(members =>{
      this.groupsList = members;
      for (let g of this.groupsList){
        if (g.id === this.userService.usersGroupId){
          this.isAuthorizedUser = true;
          this.router.navigate(['/workItem']);
        }
        if (g.id === this.userService.adminGroupId){
          this.isAdminUser = true;
        }
      }
      this.logUserInfo();   <---- ANTI-PATTERN
     });

  }

  getDisplayName(){
    this.userService.getSignedInAzureADUser().subscribe(
      (user) => this.userDisplayName = user.displayName,
      (error: any) => {
        return console.log(' Error: ' + JSON.stringify(<any>error));
    });
  }

  logUserInfo(){
    var audit = new UserAudit();
    audit.Application = this.applicationName;
    audit.Environment = "UI";
    audit.EventType= "Authorization";
    audit.UserId = this.userDisplayName;
    audit.Details = ` User Is Authorized: ${this.isAuthorizedUser}, User Is Admin: ${this.isAdminUser}`;

    this.auditService.logUserInfo(audit)
    .subscribe({ 
      next: (id)=> console.log('Id created: '+ id),
      error: (error: any) => console.log(' Error: ' + JSON.stringify(<any>error) )
    });
  }
}

【问题讨论】:

  • 为什么不在 Observable 中使用 map 运算符并修改数据?你能发布你的 Observable 源吗?
  • 我个人建议使用 ngrx Statemanagement 来完成此类任务。链接动作比加入响应要容易得多。当然,测试它们更容易。
  • @Robertgarcia 我已经发布了源 observable,或者当你要求源 observable 时我认为你的意思。它显示了我必须如何从另一个 API 中获取原始数据。
  • @MoxxiManagarm 感谢您的评论。我没有使用你说的技术。

标签: angular typescript rxjs rxjs-observables


【解决方案1】:

我发现这个问题是因为我正在搜索为什么某些 subscribe 代码块在没有明显原因的情况下被多次执行。

我发现这是由于服务返回了一些尚未加载正确数据的Observables。因此,我通过 auditTime 解决了这个问题:

忽略duration 毫秒的源值,然后从源Observable发出最新值。

因此,使用问题的代码,可以使用该运算符添加 pipe

import { auditTime, ... } from 'rxjs/operators';

this.userService.getGroupMembershipsForUser().
 .pipe(auditTime(1E3)) // delays for 1 second and gets the most recent value
 .subscribe(members => { ... });

【讨论】:

    【解决方案2】:

    你可以使用 forkJoin https://www.learnrxjs.io/operators/combination/forkjoin.html

    forkJoin({
       displayName: this.userService.getSignedInAzureADUser() // This will give you the 
       observable subscription value,
       groupMemberShip:this.userService.getGroupMembershipsForUser() 
    })
    

    订阅该 forkJoin 后,您将获得一个包含所有值的对象,您可以从中调用 logUserInfo,所有可观察对象都需要完成()才能发出 forkJoin

    【讨论】:

      猜你喜欢
      • 2020-08-18
      • 2023-03-23
      • 2020-05-31
      • 2020-10-07
      • 2019-10-03
      • 1970-01-01
      • 2019-08-20
      • 2019-02-24
      • 2023-01-11
      相关资源
      最近更新 更多