我有以下代码:
this.hubService.sendScopedCommand(Constants.hangarCommands.getHangarsOfPlayer).then((result: ICommand) => {
let hangars: IHangar[] = result.arguments[0];
for (let hangar of hangars) {
this.pieceService.getGroupedPieces(hangar.pieces).subscribe(group => hangar.groupedPieces = group);
}
this.hangars$.next(hangars);
}, (ex: any) => this.hangars$.error(ex));
基本上,sendScopeCommand
通过websocket发送内容,并且当在websocket上收到响应时执行then
函数。此时,我得到了一个放在hangars
的对象数组。
在这些对象中,我有一个玩家拥有的所有棋子的数组。可能有多件具有相同的部件类型,因此我创建了一个功能来对它们进行分组:getGroupedPieces
。其代码如下:
public getGroupedPieces(pieces: IPiece[]): Observable<IGroupedPiece[]> {
return Observable
.from(pieces)
.groupBy(p => p.pieceTypeId)
.flatMap(p => p.toArray())
.map(p => { return <IGroupedPiece>{ amount: p.length, piece: p[0] }; })
.toArray();
}
此代码有效,但我确定它不正确。实际上,我认为hangars
甚至在for
循环中的observable完成之前就会在observable上发出。
我在这里想要的是等待所有这些observable完成,然后在Observable上发出hangars
。
答案 0 :(得分:2)
我个人尝试尽可能少地调用subscribe,特别是避免可能的订阅嵌套。
我把一个快速的角度组件拼凑在一起,给出了我将如何处理它的样本。
抱歉,如果它粗糙或拼写错误(破骨领只能单手操作。)import { Component, OnInit } from '@angular/core';
import { Observable, Subject } from 'rxjs';
interface hangar {
pieces: number[];
groupedPieces: number[];
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
//output mock
hangars$: Subject<hangar[]> = new Subject<hangar[]>();
ngOnInit() {
//proof of functionality
this.hangars$.subscribe(h => console.log(h));
}
//method to mock the then call from example
start() {
//mock some data
let hangars: hangar[] = [{ pieces: [1, 2, 3], groupedPieces: null }, { pieces: [1, 2, 3], groupedPieces: null }, { pieces: [1, 2, 3], groupedPieces: null }];
//subject to handle observable clean up
let subManagement$: Subject<any> = new Subject<any>();
let obsArr: Observable<number[]>[] = [];
//here were going to build an array the observables but not subscribe to them yet
hangars.forEach(hangar =>
obsArr.push(
this.getGroupedPieces(hangar.pieces)
.takeUntil(subManagement$)
.do(group => hangar.groupedPieces = group)
)
);
//real magic, this waits for all of the observables responses before emitting its value
Observable.combineLatest(obsArr).subscribe(
() => this.hangars$.next(hangars),
null,
() => subManagement$.next()//cleanup
);
}
//mock out your service
private getGroupedPieces(pcs: number[]): Observable<number[]> {
return Observable.of([1, 2, 3, 4]).delay(1000);
}
}
答案 1 :(得分:0)
我认为您可以尝试使用RxJS的forkJoin
运算符:
this.hubService.sendScopedCommand(Constants.hangarCommands.getHangarsOfPlayer).then((result: ICommand) => {
let hangars: IHangar[] = result.arguments[0];
let hangars$$: Observable<IHangar>[] = hangars.map(hangar => {
return this.pieceService.getGroupedPieces(hangar.pieces)
})
Observable
.forkJoin(...hangars$$)
.subscribe(groups => {
groups.forEach((group, i) => hangars[i].groupedPieces = group)
this.hangars$.next(hangars);
})
}, (ex: any) => this.hangars$.error(ex));