在 RxJS Observable 中 "flatten" 数组的最佳方式

Best way to "flatten" an array inside an RxJS Observable

我的后端经常 returns 数据作为 RxJS 5 Observable 中的 数组(我正在使用 Angular 2)。

我经常发现自己想使用 RxJS 运算符单独处理数组项,我使用以下代码 (JSBin):

const dataFromBackend = Rx.Observable.of([
  { name: 'item1', active: true },
  { name: 'item2', active: false },
  { name: 'item3', active: true }
]);

dataFromBackend
  // At this point, the obs emits a SINGLE array of items
  .do(items => console.log(items))
  // I flatten the array so that the obs emits each item INDIVIDUALLY
  .mergeMap(val => val)
  // At this point, the obs emits each item individually
  .do(item => console.log(item))
  // I can keep transforming each item using RxJS operators.
  // Most likely, I will project the item into another obs with mergeMap()
  .map(item => item.name)
  // When I'm done transforming the items, I gather them in a single array again
  .toArray()
  .subscribe();

mergeMap(val => val) 行感觉不是很地道。

是否有更好的方法将转换应用于 Observable 发出的数组成员?

注意。我希望 RxJS 运算符(相对于数组方法)来转换我的项目,因为我需要能够将每个项目投影到第二个可观察对象中。典型用例:项目 ID 列表的后端 returns,我需要从后端请求所有这些项目。

您可以使用不带任何参数的 concatAll()mergeAll()

dataFromBackend.pipe(
  tap(items => console.log(items)),
  mergeAll(), // or concatAll()
)

这(包括 mergeMap)仅适用于 RxJS 5,因为它以相同的方式处理 Observable、数组、类数组对象、Promises 等。

最后你也可以这样做:

mergeMap(val => from(val).pipe(
  tap(item => console.log(item)),
  map(item => item.name),
)),
toArray(),

2019 年 1 月:针对 RxJS 6 更新

如果是同步操作,我建议改用javascript的Array.map,它甚至可以节省一些性能:

const dataFromBackend = Rx.Observable.of([
  { name: 'item1', active: true },
  { name: 'item2', active: false },
  { name: 'item3', active: true }
]);

dataFromBackend
  .map(items => items.map(item => item.name))
  .subscribe();

实际上,如果您在流中需要它,只需使用它:

.flatMap(items => of(...items))

Angular 6 个音符。

如果您用作管道运算符,do 称为 tap!

https://www.learnrxjs.io/operators/utility/do.html 这是一个例子。

// RxJS 
import { tap, map, of, mergeMap} from 'rxjs/operators';

backendSource
  .pipe(
   tap(items => console.log(items)),
   mergeMap(item => item ),
   map(item => console.log(item.property))
  );

我遇到了类似的问题:

以下

  • 对每个项目运行,
  • 采摘深度嵌套的对象
  • 将服务器响应转换为数组
  • 在模板中作为异步管道使用
    this.metaData = backendPostReq(body)
      .pipe(
        mergeMap(item => item),   // splits the array into individual objects
        pluck('metaData', 'dataPie', 'data'), // plucks deeply nested property
        toArray()  // converted back to an array for ag grid
      )

    <ag-grid-angular
        *ngIf="metaData | async as result"
        [gridOptions]="dataCollectionConfig"
        [rowData]="result"
        [modules]="modules"
        class="ag-theme-balham data-collection-grid"
    >
    </ag-grid-angular>