Angular RxJS主题完成后自动关闭订阅

Angular RxJS主题完成后自动关闭订阅,angular,rxjs,Angular,Rxjs,我在一个服务中公开了两个主题,因此我可以呈现主题中的值并在页面上呈现它们 其中一个主题正确接收信息,但第二个主题自动关闭订阅,我无法再检索数据 这是我的代码: // service.ts clientSubject: Subject<any>; jobSubject: Subject<any>; constructor(private clientService: ClientService, private jobService: JobService)

我在一个服务中公开了两个主题,因此我可以呈现主题中的值并在页面上呈现它们

其中一个主题正确接收信息,但第二个主题自动关闭订阅,我无法再检索数据

这是我的代码:

// service.ts
  clientSubject: Subject<any>;
  jobSubject: Subject<any>;

  constructor(private clientService: ClientService, private jobService: JobService) {
    this.clientSubject = new Subject();
    this.jobSubject = new Subject();
  }

  fetchData(): void {
    this.clientService.getClients()
    .pipe(
      map(clients => clients.map(
        client => this.jobService.getJobs(client.clientId)
          .pipe(
            map(jobs => jobs.map(job => ({client, job})))
          )
          .subscribe(this.jobSubject)
        )
    ))
    .subscribe(this.clientSubject);
  }
这是控制台记录的内容:

### this.jobs data ###
invoices.component.ts:25 
[{…}]
0: {client: {…}, job: {…}}
length: 1
__proto__: Array(0)


### this.clients data ###
invoices.component.ts:19 
(2) [SubjectSubscriber, SubjectSubscriber]
0: SubjectSubscriber {closed: true, _parentOrParents: null, _subscriptions: null, syncErrorValue: null, syncErrorThrown: false, …}
1: SubjectSubscriber {closed: true, _parentOrParents: null, _subscriptions: null, syncErrorValue: null, syncErrorThrown: false, …}
length: 2
__proto__: Array(0)
为什么基于
fetchData
中的实现,SubjectSubscribers会覆盖
this.clients
数据

jobService.getJobs(client.clientId)
返回以下格式的可观察值:

[{jobId: 1, name: 'blabla', items: []}]
[{clientId: 1, name: 'blabla', isParent: false}]
jobService.getClients()
返回具有以下格式的可观察对象:

[{jobId: 1, name: 'blabla', items: []}]
[{clientId: 1, name: 'blabla', isParent: false}]

现在。Map正在将客户端数组转换为订阅数组。这就是
clients.map([…]
)正在做的。可能让您困惑的是
.subscribe
返回一个值?如下所示:

const valueReturnedBySubscribe = anyObservable.subscribe(LAMBDA);
console.log(valueReturnedBySubscribe);
输出:

SubjectSubscriber {closed: true, [...]
请尝试以下方法:

fetchData(): void {
  this.clientService.getClients().pipe(
    tap(clients => clients.forEach(
      client => this.jobService.getJobs(client.clientId)
        .pipe(
          map(jobs => jobs.map(job => ({client, job})))
        )
        .subscribe(this.jobSubject)
      )
    )
  )
  .subscribe(this.clientSubject);
}
点击
根本不会更改您的流,而且您似乎也不需要订阅对象。不确定为什么要使用地图,但看起来您并不需要它


更新 让jobSubject订阅clientSubject可能最有意义,因为新客户端总是意味着查询新作业。这可能类似于:

clientSubject: Subject<any>;
jobSubject: Subject<any>;

constructor(private clientService: ClientService, private jobService: JobService) {

  this.clientSubject = new Subject();
  this.jobSubject = new Subject();

  this.clientSubject.pipe(
    map(clients => clients.map(
      client => jobService.getJobs(client.clientId).pipe(
        map(jobs => jobs.map(job => ({client, job})))
      )
    )),
    mergeMap(jobs => merge(jobs))
  ).subscribe(this.jobSubject);
}

fetchData(): void {
  this.clientService.getClients().subscribe(this.clientSubject);
}


这里有很多问题

  • 您正在从
    映射(客户端…
    返回订阅,该订阅随后被推送到
    this.clientSubject

  • getClients()
    函数返回的数组会触发多个订阅。您可以使用
    forkJoin
    函数并行触发多个观察值

  • 您可以
    switchMap
    来链接可观察对象,而不是嵌套订阅

  • 试试下面的方法

    fetchData():void{
    此.clientService.getClients()管道(
    点击(clients=>this.clientSubject.next(clients)),//forkJoin(clients.map(client=>//jobs.map(job=>({client,job})))
    )
    )))
    ).订阅(
    jobs=>this.jobSubject.next(作业)
    );
    }
    
    一个区别是,
    jobSubject
    现在将发出一个作业数组,其形式为
    [{client,job},{client,job},…]

    更新:在每个源通知上发出 您可以使用
    点击
    操作员的
    下一步
    错误
    完成
    回调向相应的主题发出每个相应的通知

    fetchData():void{
    此.clientService.getClients()管道(
    轻触({//this.clientSubject.next(clients),
    error:error=>this.clientSubject.next(error),
    complete:()=>this.clientSubject.complete()
    }),
    switchMap(clients=>forkJoin(clients.map(client=>//jobs.map(job=>({client,job}))),
    水龙头({
    next:jobs=>this.jobSubject.next(jobs),
    error:error=>this.jobSubject.error(error),
    
    complete:()=>this.jobSubject.complete()//与
    observable.subscribe(subject)
    不同,这不会传递
    错误()
    完成()
    发射到他的受试者身上。@MrkSef:我已经更新了答案,使用
    点击
    来发射两个源观测到的相应类型的通知。是的,这总是一个很好的舞蹈:“我应该准确回答海报上的问题,还是应该回答我认为他们想问的问题?”-我想你是对的,他不希望他的受试者在一个可观测的源完成的那一刻完成。
    this.clientService.getClients().subscribe(this.clientSubject);
    to
    this.clientService.getClients().subscribe(this.clientSubject.next);