forkJoin不等待所有可观察对象完成

时间:2020-03-08 10:23:27

标签: typescript rxjs


import { Component } from "@angular/core";
import { Observable, of, throwError, Subscription, forkJoin } from "rxjs";
import { mergeMap, map, delay, timeout, first, take } from "rxjs/operators";
import { ajax } from "rxjs/ajax";

class Test {
  id: number;
  firstObj: FirstObj;
  secondObj: SecondObj;
  thirdObj: string;
}

interface FirstObj {
  firstObs: boolean;
  result: string;
}

interface SecondObj {
  secondObs1: boolean;
  secondObs2: boolean;
}

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  private workOrderSubscription: Subscription;
  name = "Angular";
  obsOne: Observable<any> = of("First Obs")
    .pipe(delay(6000))
    .pipe(
      map(res => {
        return {
          firstObs: true,
          result: res
        };
      })
    );

  dataTwo: SecondObj = { secondObs1: true, secondObs2: false };

  obsTwo: Observable<any> = of(this.dataTwo);
  obsThree: Observable<any> = of("error");

  private getId(): Observable<any> {
    return of("id" as string);
  }

  public retrieveWork(): Observable<Test> {
    const test: Test = new Test();
    this.getId().subscribe((id: number) => {
      test.id = id as number;
      forkJoin(this.obsOne, this.obsTwo, this.obsThree).subscribe(
        ([first, second, third]: [FirstObj, SecondObj, string]) => {
          // some appropriate checks here
          test.firstObj = first as FirstObj;
          test.secondObj = second as SecondObj;
          test.thirdObj = third as string;
          console.log("first is " + first.result);
          console.log("second is " + second.secondObs1);
          console.log("third is " + third);
          console.log(`inside ******************** ${JSON.stringify(test)}`);
          return of(test);
        },
        error => {
          //error here
          console.log("GOT ERROR");
        }
      );
    });

    console.log(`returning ******************** ${JSON.stringify(test)}`);
    return of(test);
  }

  ngOnInit() {
    console.log("data ************************");
    this.retrieveWork()
      .pipe(timeout(10000))
      .subscribe(data => {
        {
          console.log("printing data ***************************");
          console.log(`${JSON.stringify(data)}`);
        }
      });
  }
  ngOnDestroy() {}
}


我尝试了很多方法,基本上我想做的是在ngOnInit中,我正在订阅get(),但是我得到的数据并不完整。订阅不会等到forkJoin完全返回。我不确定如何获取完整的数据。

在完成第一个订阅后,我希望第一个订阅和第二个订阅都完成,然后填充“ Test”类,然后在ngOnInit中填充我的订阅者以获取数据。

我的输出看起来像这样

数据************************

返回******************** {“ id”:“ id”}

打印数据***************************

{“ id”:“ id”}

首先是初次观察

秒是正确的

第三个是错误

inside ******************** {“ id”:“ id”,“ firstObj”:{“ firstObs”:true,“ result”:“ First Obs“},” secondObj“:{” secondObs1“:true,” secondObs2“:false},” thirdObj“:”错误“}

正如我们在上面的输出中看到的那样,只有id被打印出来(第一次订阅后), 但是在第二次订阅之后,ngOnInit中的订阅者不再获取数据。

谢谢。

2 个答案:

答案 0 :(得分:1)

我将嵌套的Observable替换为高阶映射运算符(switchMap),它似乎可以正常工作。 (但是我不清楚应该输出什么。)

这就是我所拥有的:

opts

这能达到您的期望吗?

答案 1 :(得分:0)

最后,这似乎可行。我是RXJS的新手。欢迎任何建议。

还处理了所有错误情况。

import { Component } from "@angular/core";
import {
  Observable,
  of,
  throwError,
  Subscription,
  forkJoin,
  combineLatest
} from "rxjs";
import {
  mergeMap,
  map,
  delay,
  timeout,
  first,
  take,
  catchError
} from "rxjs/operators";
import { ajax } from "rxjs/ajax";

class Test {
  id: number;
  firstObj: FirstObj;
  secondObj: SecondObj;
}

interface FirstObj {
  firstObs: boolean;
  result: string;
}

interface SecondObj {
  secondObs1: boolean;
  secondObs2: boolean;
}

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  private workOrderSubscription: Subscription;
  name = "Angular";

  dataone: FirstObj = { firstObs: true, result: "hai" };
  obsOne: Observable<any> = of(this.dataone).pipe(delay(1000));
  dataTwo: SecondObj = { secondObs1: true, secondObs2: false };
  obsTwo: Observable<any> = throwError(this.dataTwo);

  private getId(): Observable<any> {
    return of(1).pipe(delay(4000));
  }

  public get(): Observable<any> {
    let test: Test = new Test();
    return new Observable(subscriber =>
      this.getId().pipe(timeout(5000)).subscribe(
        (id: number) => {
          test.id = id;
          forkJoin(
            this.obsOne.pipe(timeout(1000)).pipe(catchError(error => of(null))),
            this.obsTwo.pipe(timeout(1000)).pipe(catchError(error => of(null))),
          ).subscribe(([first, second]) => {
            test.firstObj = first;
            test.secondObj = second;
            console.log("printing data ***************************2");
            console.log(`${JSON.stringify(test)}`);
            subscriber.next(test);
            subscriber.complete();
          });
        },
        err => {
          console.log("error while getting data");
          subscriber.error("error while getting data");
          subscriber.unsubscribe();
        }
      )
    );
  }

  ngOnInit() {
    let subscription: Subscription = this.get()
      .pipe(timeout(6000))
      .subscribe(
        (data: Test) => {
          console.log("in subscribe");
          console.log(`${JSON.stringify(data)}`);
        },
        err => {
          console.log("ERROR " + err);
          subscription.unsubscribe();
        }
      );
  }
  ngOnDestroy() {}
}