角度-从可观察的可观察对象中获取可观察的数组

时间:2019-10-15 08:24:04

标签: angular rxjs observable

我必须在一个数组中递归列出所有生成的observable,以便稍后执行所有这些操作。

有关更多上下文,对象currentLesson具有活动列表。但是一个activity可以是另一个lesson,并具有其他作为孩子的活动。使用前,我必须(深入)加载所有活动。这就是为什么我要使用递归函数。

这是我的代码,但是在构建结束时出现错误。我理解错误,但是我不知道为什么dataObservable<Observable<DataEntity>>而不是Observable<DataEntity>[],而且我也不知道该怎么做。

代码:

        const recursivelyGetActivityObservales = (currentLesson: DataEntity): Observable<DataEntity>[] => {
            const obsList: Observable<DataEntity>[] = [];

            const activities: any[] = currentLesson.get('reference');
            for (const activity of activities) {
                if (activity['type'] === 'lesson') {
                    const data = this.getLessonById(activity.id).flatMap(subLesson =>  recursivelyGetActivityObservales(subLesson));
                    obsList.push(...data);
                } else {
                    const loadedActivity = this.activitiesService.getActivityEntity(+activity.id);

                    if (loadedActivity) {
                        obsList.push(from([loadedActivity]));
                    } else {
                        obsList.push(this.activitiesService.loadActivitiesFromId(activity.id));
                    }
                }
            }

            return obsList;
        }

错误:

ERROR in src/app/@modules/activities/core/lessons/lessons.service.ts(321,37): error TS2461: Type 'Observable<Observable<DataEntity>>' is not an array type.

1 个答案:

答案 0 :(得分:0)

在这一行:

const data = this.getLessonById(activity.id)
                 .flatMap(subLesson => recursivelyGetActivityObservales(subLesson));

函数recursivelyGetActivityObservales(subLesson)返回的是数组,而不是Observable。 FlatMap / mergeMap操作员需要返回可观察的才能正常工作。

我不知道您将如何处理最终的可观察值数组,但是无论如何如果要进行合并,一种快速的解决方案是使用merge()运算符。示例:

const lessons = (activity) => [
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4])
]

const activity = rxjs.of('activity1');

const toSub = activity.pipe(rxjs.operators.mergeMap((activity) => rxjs.merge(...lessons(activity))))

toSub.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.js"></script>

在您的代码中:

const data: Observable<DataEntity> = this.getLessonById(activity.id)
             .flatMap(subLesson =>  merge(...recursivelyGetActivityObservales(subLesson)));
obsList.push(data);

首选解决方案:

说,IMO正确的解决方案将仅返回类型Observable<DataEntity>,因为它还表示多个DataEntity对象。在这种用例中,没有理由要有一系列可观察对象。

为此,我只返回合并列表。 示例:

const recursivelyGetActivityObservales = (currentLesson: DataEntity): Observable<DataEntity> => {
    const obsList: Observable<DataEntity>[] = [];

    const activities: any[] = currentLesson.get('reference');
    for (const activity of activities) {
        if (activity['type'] === 'lesson') {
            const data = this.getLessonById(activity.id).flatMap(subLesson =>  recursivelyGetActivityObservales(subLesson));
            obsList.push(data);
        } else {
            const loadedActivity = this.activitiesService.getActivityEntity(+activity.id);

            if (loadedActivity) {
                obsList.push(from([loadedActivity]));
            } else {
                obsList.push(this.activitiesService.loadActivitiesFromId(activity.id));
            }
        }
    }

    return merge(...obsList);
}

外植体

Observable<DataEntity>是一种数据结构,它通过调度程序发出DataEntities(0、1或许多)。实际上是DataEntities的容器(如数组)。 以以下示例为例,其中两个数据结构等于相同的输出结果:

const lessonObsArray =  [ // Observable<DataEntity>[]
    rxjs.of(1),
    rxjs.of(2),
    rxjs.of(3),
    rxjs.of(4),
]

const lessonObs = rxjs.merge( // Observable<DataEntity>
    rxjs.of(1),
    rxjs.of(2),
    rxjs.of(3),
    rxjs.of(4)
);

lessonObsArray.forEach(obs => obs.subscribe(console.log))
console.log('--------')
lessonObs.subscribe(console.log)
// They emit the same!!! (a collection of numbers in this case)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.js"></script>

希望这会有所帮助!