在 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>
我的后端经常 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>