简体   繁体   English

RXJS 在管道内组合多个可观察对象

[英]RXJS Combining multiple observables inside a pipe

I have an API call that returns a certain amount of ids.我有一个返回一定数量 id 的 API 调用。 Each of these ids are used to make a new api call.这些 id 中的每一个都用于进行新的 api 调用。 The results of these API calls need to be combined into a single object.这些 API 调用的结果需要组合成一个对象。

At first I used a loop inside the .pipe(map) operator of the first api call.起初,我在第一个 api 调用的 .pipe(map) 运算符中使用了一个循环。 In this loop I did the second api calls, and in the .pipe(map) operator in each of these calls I would edit a variable in my angular component.在这个循环中,我进行了第二个 api 调用,并且在每个调用的 .pipe(map) 运算符中,我将在我的 angular 组件中编辑一个变量。

This wasn't very pretty, and I was actually wondering if this is thread safe.这不是很漂亮,我实际上想知道这是否是线程安全的。 I know javascript is single threaded, but it doesn't seem very safe to have multiple asynchronous processes messing with the same global variable.我知道 javascript 是单线程的,但是让多个异步进程混淆同一个全局变量似乎不太安全。

after that I just stored the observable returned by the second api call in an array by looping over the returned Ids by apiCall1, and used forkJoin to subscribe and handle each result accordingly (see example).之后,我只是通过循环 apiCall1 返回的 Id 将第二个 api 调用返回的 observable 存储在数组中,并使用 forkJoin 订阅并相应地处理每个结果(参见示例)。

This isn't very pretty however, and I was wondering if there's an operator I can use in my pipe for this?然而,这不是很漂亮,我想知道是否有我可以在我的管道中使用的运算符?

So instead of (pseudocode):所以而不是(伪代码):

  .pipe(
      map(ids=> {

        let observables = []
        for (const id of ids) {
         observables.push(this.service.getSomeStuff(id));
        }

        forkJoin(...observables).subscribe(dataArray) => {
          for (data of dataArray) {
            //Do something
          }
        });

      }),
      takeWhile(() => this.componentActive),
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
    )
    .subscribe();

Is there an operator that makes it something like this:是否有一个运算符使它像这样:

  .pipe(
      map(ids=> {

        let observables = []
        for (const id of ids) {
         observables.push(this.service.getSomeStuff(id));
        }

      return observables
      }),
      forkJoin(dataArray => {
          for (data of dataArray) {
            //Do something
          }
        });
      takeWhile(() => this.componentActive),
      catchError(error => {
        console.log(error);
        return throwError(error);
      })
    )
    .subscribe();

This is what you can do:这是你可以做的:

sourceObservable$.pipe(
  // depends on your need here you can use mergeMap as well
  switchMap(ids => {
    const observables = ids.map(i => this.service.getSomeStuff(id));
    return forkJoin(observables);
  }),
  tap(joined => {
    // joined will be an array of values of the observables in the same
    // order as you pushed in forkJoin
    for (data of joined) {
      // do something
    }
  }),
  takeWhile(() => this.componentActive),
  catchError(error => {
    console.log(error);
    return throwError(error);
  })
)
.subscribe();
combineLatest(...observables)

只会在所有 observable 发出后才会发出,并且您将拥有一个结果数组。

Instead of modifying your data at once using for, why don't you do it as the data is received?与其使用 for 立即修改您的数据,不如在收到数据时进行修改? Something like this.像这样的东西。

source$.pipe(
  mergeMap(ids => from(ids)),
  mergeMap(id => this.service.getSomeStuff(id)),
  tap(data => //do someting with the data);
  takeWhile(() => this.componentActive),
  catchError(error => {
    console.log(error);
    return throwError(error);
  }),
  toArray(), --> this create the array of all the values received.
)
.subscribe(data => //returns array of modified data);

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM