簡體   English   中英

有什么辦法可以避免嵌套訂閱嗎?

[英]Is there any way to avoid nested subscribe?

( 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 作為我的后端,我將不得不通過不同的 collections 查詢來獲取我的數據。 例如,第一個訂閱只獲取用戶課程注冊數據,如 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 是如何工作的。

我創建了一個解決方案,通過執行以下操作來防止嵌套管道以及多個顯式訂閱:

  • 我結合switchMapforkJoin
  • 我將部分代碼外包給輔助方法getMergedCourseDetails()以保持主要 pipe 平坦
/* 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))
    );
}

如果您使用嵌套訂閱,則意味着它將等待第一個返回值,然后調用第二個,依此類推。 這會花費很多時間。 您可以在此使用的是 forkJoin():

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

forkJoins 等待所有 3 個 Observables 發出一次並為您提供所有值。 這里的例子: https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM