firebase 有没有办法避免嵌套订阅?

j2cgzkjk  于 2022-12-04  发布在  其他
关注(0)|答案(2)|浏览(114)

https://i.stack.imgur.com/2zm2w.png)(英文)

collectionData(queryRef).subscribe((data) => {
  for (const each of data) {
    this.getCourse(each.courseId)
      .pipe(take(1))
      .subscribe((courseData) => {
        const course = courseData[0];
        console.log(course);
        this.getLecturer(course.lecturerId).pipe(take(1)).subscribe((res: any)=>{
          const lecturer = res[0];
          course.lecturerName = lecturer.lecturerName;
          course.lecturerImageUrl = lecturer.lecturerImageUrl;
        });
        recentVisit.push(course);
      });
  }
});

嗨,我还是Angular的rxjs新手。我正在使用Angular Fire构建一个Ionic应用程序。我目前面临一些问题,我使用Firebase作为我的后端,我必须通过不同的集合来查询我的数据。例如,第一个订阅只获取用户课程注册数据,如courseId,progress...,第二个订阅将获取课程详细信息,第三个将获取讲师的详细信息。有人能给予一些建议如何避免使用嵌套订阅吗?因为很多人说不建议这样做。如果你能提供一些详细的解释,我将非常感激,因为我真的只知道rxjs的基础知识。
我尝试过concatMap,但它显示firebase错误(https://i.stack.imgur.com/6SOS0.png)]

collectionData(queryRef)
  .pipe(
    concatMap((res: any) => this.getCourse(res.courseId))
    //concatMap((result2: any) => this.getLecturer(result2.lecturerId))
  )
  .subscribe((res) => {
    console.log(res);
  });

但实际上我也不确定我做得对不对,因为我真的不能理解concatMap是如何工作的。

afdcj2ne

afdcj2ne1#

我创建了一个解决方案,通过执行以下操作来防止嵌套管道和多个显式订阅:

  • 我把switchMapforkJoin结合起来
  • 我将部分代码外包给helper-method getMergedCourseDetails(),以便保持主管道的平整
/* Initialize all information about the courses */

ngOnInit(): void {
    this.collectionData(this.queryRef).pipe(
        switchMap(data => {
            if (data.length) {

                // Create an observable (backend-request) for each course-id:
                const courseObs = data.map(c => this.getCourse(c.courseId));

                // Execute the array of backend-requests via forkJoin():
                return courseObs.length ? forkJoin(courseObs) : of([]);
            }
            return of([]);
        }),
        switchMap((courseDataList: Course[][]) => {         
            if (courseDataList.length) {

                // Get the first course from each course array (as defined in SO question):
                const courses = courseDataList.filter(c => c.length).map(c => c[0]);

                // Create observables to retrieve additional details for each of the courses:
                const detailInfoObs = courses.map(c => this.getMergedCourseDetails(c));

                // Execute the created observables via forkJoin():
                return detailInfoObs.length ? forkJoin(detailInfoObs) : of([]);
            }
            return of([]);
        }),
        tap((courseList: Course[]) => {
            courseList.forEach(d => {
                console.log('Lecturer Id:', d.lecturerId);
                console.log('Lecturer Name:', d.lecturerName);
                console.log('Lecturer ImageUrl:', d.lecturerImageUrl);
            });
        })      
    )
    .subscribe();
}

/* Enrich existing course-data with lecturer-details */

private getMergedCourseDetails(course: Course): Observable<Course> {
    return this.getLecturer(course.lecturerId).pipe(                            
        map(lecturers =>            
            // Merge existing course-data with newly retrieved lecturer-details:            
            ({...course,
                lecturerName: lecturers[0]?.lecturerName ?? '', 
                lecturerImageUrl: lecturers[0]?.lecturerImageUrl ?? '' } as Course))
    );
}
unguejic

unguejic2#

如果你使用嵌套的订阅,这意味着它将等待第一个订阅返回一个值,然后调用第二个订阅,如此类推。这会花费很多时间。你可以在这里使用forkJoin():

forkJoin(
 {
   a: this.http.call1()..
   b: this.http.call2()..
   c: this.http.call3()..
 }).subscribe()

forkJoins等待所有3个Observable发出一次,并给出所有值。示例如下:https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin

相关问题