简体   繁体   English

RxJS forkJoin piped observables

[英]RxJS forkJoin piped observables

I need to make a number of calls to the server to save some data, and each subsequent call requires some data from the result of the previous call.我需要对服务器进行多次调用以保存一些数据,并且每次后续调用都需要来自上一次调用结果的一些数据。 Tried to use forkJoin, but the sequence of events does not makes sense (at least to me).尝试使用 forkJoin,但事件顺序没有意义(至少对我而言)。 I figure the problem is with the.pipe() call where I'm trying to modify the input data for the next call.我认为问题出在 .pipe() 调用上,我正在尝试修改下一次调用的输入数据。

So I have two questions:所以我有两个问题:

  1. Why is the output not what I expected为什么 output 不是我所期望的
  2. Is there a way to make this work using forkJoin (I realize there are a dozen other ways of approaching this problem, so not really looking for an alternative solution)有没有办法使用 forkJoin 来完成这项工作(我意识到有很多其他方法可以解决这个问题,所以并不是真的在寻找替代解决方案)

Here's some sample code, or StackBlitz .这是一些示例代码或StackBlitz


  let data: { [key: string]: any } = {};

  forkJoin(
      this.saveFirst(data).pipe(
        tap(_ => console.log('saveFirst pipe after')),
        tap(result => data.id = result.id)
      ),
      this.saveSecond(data).pipe(
        tap(_ => console.log('saveSecond pipe after')),
        tap(result => data.name = result.name)
      ),
  ).subscribe(result => console.log('done: data - ', JSON.stringify(data)));

...

  private saveFirst(data: { [key: string]: any }): Observable<any> {
      console.log('saveFirst: start');
      console.log('saveFirst: data - ', JSON.stringify(data));

      // replaced call to server with "of({ id: 1 })" for simplicity of example
      return of({ id: 1 }).pipe(tap(_ => console.log('saveFirst: end')));
  }

  private saveSecond(data: { [key: string]: any }): Observable<any> {
      console.log('saveSecond: start');
      console.log('saveSecond: data - ', JSON.stringify(data));

      // replaced call to server with "of({ name: 'test' })" for simplicity of example
      return of({ name: 'test' }).pipe(tap(_ => console.log('saveSecond: end')));;
  }

I was expecting the following output:我期待以下 output:

saveFirst: start
saveFirst: data -  {}
saveFirst: end
saveFirst pipe after

saveSecond: start
saveSecond: data - {}
saveSecond: end
saveSecond pipe after

done: data -  {"id":1,"name":"test"}

But instead got this:但是得到了这个:

saveFirst: start
saveFirst: data -  {}
saveSecond: start
saveSecond: data -  {}

saveFirst: end
saveFirst pipe after
saveSecond: end
saveSecond pipe after

done: data -  {"id":1,"name":"test"}

You need to use mergeMap / switchMap in this case.在这种情况下,您需要使用mergeMap / switchMap

this.saveFirst(data).pipe(
          tap(_ => this.actions.push('saveFirst pipe after')),
          tap(result => data.id = result.id),
          switchMap((res)=>{
            return this.saveSecond(data).pipe(
          tap(_ => this.actions.push('saveSecond pipe after')),
          tap(result => data.name = result.name)
        );
          })).subscribe(result => this.actions.push('done: data - ' + JSON.stringify(data)));

The above code will produce the result you need.上面的代码会产生你需要的结果。 forkJoin is used when we want to issue multiple requests and only care about the final result.当我们想要发出多个请求并且只关心最终结果时使用forkJoin

Forked Stackblitz .分叉的Stackblitz

If order of execution is important, you need to use concatMap instead of forkjoin如果执行顺序很重要,则需要使用 concatMap 而不是 forkjoin

this.saveFirst(data).concatMap(() => this.saveSecond(data)).subscribe()

https://www.learnrxjs.io/learn-rxjs/operators/transformation/concatmap which mentions using concatMap when order is important. https://www.learnrxjs.io/learn-rxjs/operators/transformation/concatmap提到在订单很重要时使用 concatMap。

I've been struggled with the same issue, the only solution I found is without piping the observables, but handle all responses after subscribing the forjoin.我一直在为同样的问题而苦苦挣扎,我找到的唯一解决方案是不使用管道传输 observables,而是在订阅 forjoin 后处理所有响应。

It will run both tasks in parallel , and not sequently like above solutions.它将并行运行这两个任务,而不是像上述解决方案那样依次运行。 I moved your handling from 'tap' to new handling methods, and called them once forkJoin subscription finished.我将您的处理从“点击”转移到新的处理方法,并在 forkJoin 订阅完成后调用它们。

yourMethod()
{
    let data: { [key: string]: any } = {};

    forkJoin(
        this.saveFirst(data),
        this.saveSecond(data)
    ).subscribe(([res1, res2]) =>
    {
        this.handleSuccess_1(res1, data);
        this.handleSuccess_2(res2, data);
        console.log('done: data - ', JSON.stringify(data));
    });
}

handleSuccess_1(res, data)
{
    console.log('saveFirst pipe after');
    data.id = res.id;
}

handleSuccess_2(res, data)
{
    console.log('saveSecond pipe after');
    data.name = res.name;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 RxJS forkjoin observables 未检索到 - RxJS forkjoin observables not retrieving 我可以将 map 与 Observables 一起通过管道传输到 mergeMap -&gt; forkJoin 并将 object 传递到 RxJs 的下游吗? - Can I both map to Observables, that are piped into mergeMap -> forkJoin AND pass an object to the downstream in RxJs? RxJs fork 连续加入几个 observables - RxJs forkJoin several observables in a row 如果 RxJS forkjoin 正在等待的可观察对象之一中有 flatMap,则它会停止订阅 - RxJS forkjoin stops subscribing if theres a flatMap inside one of the observables it is waiting for Angular 9 rxjs - forkJoin 返回 Observables 数组而不是值数组 - Angular 9 rxjs - forkJoin returns array of Observables instead of array of values rxjs传递forkjoin一个函数,该函数返回一个可观察值数组 - rxjs pass forkjoin a function which return a array of observables 从 BehaviorSubject 创建的 Angular 2 rxjs observable 不适用于 forkJoin - Angular 2 rxjs observables created from BehaviorSubject are not working with forkJoin 执行后,Angular Rxjs通过forkJoin从Observables数组中获取错误 - Angular Rxjs get errors from observables array via forkJoin after execution rxJs forkJoin 不会从已完成的非 null 输入 Observables 中发出任何值 - rxJs forkJoin doesn't emit any values from completed not null input Observables Angular:ForkJoin ngrx observables - Angular: ForkJoin ngrx observables
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM