如何将序列的可观察值与单个值的可观察值组合在一起,然后展平此结构

时间:2019-06-28 11:49:47

标签: typescript rxjs

我想找到最好的方法来组合两个返回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(_))

将单个用户合并到个人资料列表的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

我建议结合使用mergeMapforkJoin运算符。

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);
}