首页 > 解决方案 > Angular - 从 observable 的 observable 中获取 observables 数组

问题描述

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

对于更多上下文,该对象currentLesson有一个活动列表。但一个activity可以是另一个lesson与另一个活动作为孩子。在使用它之前,我必须(深度)加载所有活动。这就是我尝试使用递归函数的原因。

这是我的代码,但在构建结束时出现错误。我理解错误,但我不知道为什么data是 anObservable<Observable<DataEntity>>而不是 an 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.

标签: angularrxjsobservable

解决方案


在这一行:

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

该函数recursivelyGetActivityObservales(subLesson)返回一个数组,而不是 Observable。FlatMap/mergeMap 操作符需要返回一个 observable才能正常工作。

我不知道您将如何处理最终的 observables 数组,但如果您无论如何都要合并它,一个快速的解决方案是使用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 正确的解决方案只是返回 type 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);
}

解释:

An是一种数据结构,它通过调度程序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>

希望这可以帮助!


推荐阅读