Angular / RxJS:带有可观察项的嵌套服务调用

时间:2018-09-14 15:49:02

标签: angular typescript rxjs angular6 angular2-observables

我是RxJS可观察对象的新手,正在尝试解决一个相当简单的用例。

在服务中,我首先进行http调用,以返回一个项(作为可观察的项)。该项目包含ID数组,其中一些重复。对于每个不同的ID,我需要调用另一个http服务(再次返回一个observable),并将其返回值添加到原始项目中,以代替相应的ID。这些调用应并行进行。最后,每次通话结束后,我的服务应返回可观察到的原始项目,现在已包含其子项目。

要给出一个更好的主意,这就是用诺言而不是可观察到的样子:

MyService() {
    return HttpGetMainItem()
        .then(item => {
            var promises = _.uniq(item.subItems)
                 .map(sid => HttpGetSubItem(sid)
                            .then(subItem => {
                                // add to matching item.subItems
                             }));
            // wait for all promises to complete and return main item
            return Promise.all(promises).then(() => item);
        });
}

使用可观察物完成此工作的最佳方法是什么?

编辑:从答案看来,我不是很清楚。带有promises的示例只是为了清楚起见,在我的情况下,http调用实际上是Angular的HttpClient.get,因此它们返回的是observables-我正在寻找使用observables做的所有事情。

2 个答案:

答案 0 :(得分:2)

这是使用rxjs完成上述操作的一种方法。

  1. 使用from将诺言转换为可观察的东西。
  2. 在外部管道中调用switchMap,以便您可以调用另一个可观察对象并将其作为外部可观察对象的结果返回。您正在切换执行上下文。
  3. 在switchMap内像以前一样执行子项的映射,然后使用forkJoin创建所有元素的诺言的Observable。一旦所有承诺都完成,ForkJoin将发出所有结果的数组。就像promise.all
  4. 添加您以前计划做的项目,然后返回原始项目。

代码

from(HttpGetMainItem()).pipe(
    switchMap(item => 
        forkJoin(_.uniq(item.subItems).map(sid => HttpGetSubItem(sid)))
            .pipe(
                map(results => { 
                    /* add results to matching items.subItems and */
                    return item;
                })
            )
     )
);

由于需要保留根项目及其所需的嵌套,我觉得这有点笨拙。您可以使用switchMap的选择器参数来组合外部和内部可观察对象。您可以使用该参数代替在map()中使用的逻辑,并且由于两个可观察对象的结果均已传递,因此您无需进行任何进一步的嵌套。

from(HttpGetMainItem()).pipe(
    switchMap(
        item => forkJoin(_.uniq(item.subItems).map(sid => HttpGetSubItem(sid))),
        (item, results) => { 
             /* add results to matching items.subItems and */
             return item;
        }
    )
);

答案 1 :(得分:1)

我相信您需要这样的东西:

import { from, forkJoin } from 'rxjs';
import { switchMap } from 'rxjs/operators';

itemWithSubItems$ = from(HttpGetMainItem()).pipe(
    switchMap(item => {
        const promises = _.uniq(item.subItems).map(item => HttpGetSubItem(item.sid));
        return forkJoin(promises)
            .map(resultArray => item.subItems = resultArray)
            .map(_ => item);
    })
);

首先获取主要项目。然后使用forkJoin解决所有子查询并充实主要项目。之后,只需返回主要项目即可。