我想找到最好的方法来组合两个返回Observables的函数。
第一个功能定义如下:
abstract getProfiles(): Observable<ClientProfile[]>
第二个是:
abstract getUser(userId: number): Observable<User>
我想创建一个投影以便创建这样的数据结构:
interface Projection {
user: User,
profiles: ClientProfile[]
}
为此,我想优化此功能
getUserProfiles() {
this.userService.getProfiles()
.pipe(
flatMap((ps: ClientProfile[]) => {
ps.map(p => this.userService.getUser(p.userId))
// I NEED TO RETURN AN OBSERVABLE HERE:
// {user: u, ...ps}
})
)
.subscribe(_ => doSomething(_))
将单个用户合并到个人资料列表的最佳方法是什么?
答案 0 :(得分:1)
我建议结合使用mergeMap
和forkJoin
运算符。
import {map as rxMap, mergeMap} from 'rxjs/operators';
import {forkJoin} from 'rxjs';
this.userService.getProfiles().pipe(
mergeMap(profiles =>
forkJoin(profiles.map(profile =>
this.userService.getUser(profile.userId).pipe(
rxMap(user =>
({
user,
profiles
})
)
)
)
)
)
配置文件列表已映射到Array<Observable<{user, profile}>>
。
当http请求返回时,这些可观察的对象(从userService
开始)已经完成。
ForkJoin
等待这些可观察值完成,然后发出包含这些完成值的可观察值。 MergeMap通过将getUser()
创建的内部可观察对象合并到getProfiles()
的外部可观察对象中来对此可观察对象进行包装。
答案 1 :(得分:0)
您可以使用// App\Form\SkillType.php
$builder->add('example');
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$entity = $event->getData();
$form
->add('variants', EntityType::class, [
'class' => Variant::class,
// I GUESS SOMETHING HERE?
]);
});
// App\Form\VariantType.php
// And this should do something too
返回switchMap
API的Observable数组,如下所示:
getUser()
如果您不想等待所有getUser()API完成,则上述解决方案会很好地工作。即,在订阅时,您将处理每次发出的getUser()API响应(与{user,profile}一起投影)。
如果您要等待所有getUser()API完成,请使用getUserProfiles() {
this.userService.getProfiles()
.pipe(
switchMap((ps: ClientProfile[]) => {
const obs$ = ps.map(p => {
return this.userService.getUser(p.userId)
.pipe(
map(user => ({user, profile: ps}))
);
});
return obs$;
// I NEED TO RETURN AN OBSERVABLE HERE:
// {user: u, ...ps}
}),
switchMap(x => x)
)
.subscribe(_ => doSomething(_))
,如下所示:
forkJoin()
希望有帮助。
答案 2 :(得分:0)
我希望这可以为您提供帮助:
function solving() {
interface Profile {
id: number, name: string, userId: number
}
interface User {
id: number, username: string
}
const getProfiles = () => ajax('api/profiles').pipe(
pluck<AjaxResponse, Array<Profile>>('response')
);
const getUser = (id: number) => ajax(`api/users/${id}`).pipe(
pluck<AjaxResponse, User>('response')
);
getProfiles().pipe(
concatMap(perfils => from(perfils).pipe(map(p => [p, perfils]))),
mergeMap(([p, perfils]: [Profile, Profile[]]) =>
getUser(p.userId).pipe(map(u => [u, perfils])))
).subscribe(console.log);
}