【问题标题】:How to invoke function that return an Observable within a recursive function?如何在递归函数中调用返回 Observable 的函数?
【发布时间】:2021-07-09 19:12:10
【问题描述】:

我有以下遍历树状对象的函数,到目前为止它工作正常。

const traverse = async (menuInputs: MenuInput[], parent: Menu = null) => {
  for (const input of menuInputs) {
    const entity = toEntity(input, parent);
    const parentMenu = await this.menuService.create(entity).toPromise();
    if (isEmpty(input.children)) {
      continue;
    }
    await traverse(input.children, parentMenu);
  }
};

我的问题是我如何调用 this.menuService.create(entity) 方法,它实际上返回一个 Observable<Menu> 而不将其转换为 Promise,有没有 RxJS 这样做的方法?

【问题讨论】:

  • this.menuService.create(entity) 返回什么?
  • @PawanSharma:OP 已经告诉我们了;看看他问题的最后一句话。

标签: javascript typescript rxjs nestjs


【解决方案1】:

对于使用HttpService 的递归可观察调用,我有类似的东西。您可能可以使用类似的东西。

@Injectable()
export class CharacterReaderApiService implements CharacterReader {
  private characters: SwapiCharacter[] = [];
  constructor(private readonly http: HttpService) {}

  async getCharacters(): Promise<Character[]> {
    console.log('Querying the API for character data...');
    return this.callUrl('https://swapi.dev/api/people')
      .pipe(
        map((data) => {
          return data.map(this.mapPerson);
        }),
        tap(async (data) =>
          promises.writeFile(join(process.cwd(), characterFile), JSON.stringify(data)),
        ),
      )
      .toPromise();
  }

  private callUrl(url: string): Observable<SwapiCharacter[]> {
    return this.http.get<SwapiResponse>(url).pipe(
      map((resp) => resp.data),
      mergeMap((data) => {
        this.characters.push(...data.results);
        return iif(() => data.next !== null, this.callUrl(data.next), of(this.characters));
      }),
    );
  }

  private mapPerson(data: SwapiCharacter): Character {
    return {
      name: data.name,
      hairColor: data.hair_color,
      eyeColor: data.eye_color,
      gender: data.gender,
      height: data.height,
    };
  }
}

重要的是保持值的运行数组,以便以后可以引用它们。

通过使用mergeMapiif,我们能够递归调用可观察对象并根据需要处理结果。如果你不喜欢它的类变量的想法,你可以让运行数组成为callUrl(或类似)方法参数的一部分,并根据需要传递它。

【讨论】:

    【解决方案2】:

    我会努力更改 toEntity()menuService.create() 以接收子列表而不是父列表,以便我可以使用 forkJoin

    const buildMenu = (input: MenuInput) => 
      forkJoin(
        input.children.map(childInput => buildMenu(childInput, menu))
      ).pipe(
        flatMap(childMenus => this.menuService.create(toEntity(input, childMenus)))
      );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-24
      • 1970-01-01
      • 1970-01-01
      • 2019-08-23
      • 2017-11-02
      • 2017-10-29
      • 2011-01-22
      • 1970-01-01
      相关资源
      最近更新 更多