【问题标题】:Await recursive forkJoin in Angular等待Angular中的递归forkJoin
【发布时间】:2020-08-11 05:17:15
【问题描述】:

试图找出我是否可以在递归 forkJoin 中等待所有 http 调用。如何等待 forkJoin 中的所有 http 调用并接收最终结果?

目前我有类似以下的内容

public myMethod(urls: string[]) {

...

return forkJoin(observables)
        .pipe(map(() => {
          if (json.urls !== 0) {
            return this.myMethod(json.urls);
          }
        }),   catchError((err) => {
          console.log(err);
          return of(null);
        })
        );
}

And then I subscribe ...

public mainMehtod(){
  return this.myMethod([json]).pipe(map(() => {
      ...some stuff here. But I need here the final result from the finished recursion
    }));

编辑

我找到的解决方案是,在递归中收集所有可观察对象,然后调用 forkjoin。

【问题讨论】:

  • 什么是递归?
  • expand 可用于递归调用,但需要有关此函数的更多详细信息才能为您的特定情况提供工作示例

标签: angular typescript http async-await rxjs


【解决方案1】:

有一个expand 运算符可以解决您的问题。

你应该如何使用它:

import { fromEvent, of, forkJoin, EMPTY } from 'rxjs';
import { expand, delay, map, reduce, last } from 'rxjs/operators';

const DATABASE: Element[] = [
  {id:'one', childId: 'three'},
  {id:'two', childId: 'four'},
  {id:'three', childId: 'five'},
  {id:'four', childId: 'six'},
  {id:'five', childId: null},
  {id:'six', childId: null}
];

mainMethod(['one', 'two']).subscribe(value => {
  console.log(value.map(e => e.id));
})

function mainMethod(ids: string[]) {
  return forkJoin(ids.map(id => getElementById(id))).pipe(
    expand(values => {
      if (values.some(el => el.childId)) {
        return forkJoin(values
          .filter(v => v.childId)
          .map(el => getElementById(el.childId))
        )
      }
      return EMPTY;
    }),
    last() // use this if you want only last emission. Be careful, last throws an error, if no value is passed
    // reduce((acc, values) => acc.concat(values), []) // use this if you want everything
  )
}

function getElementById(id: string) {
  return of(DATABASE.find(el => el.id === id)).pipe(
    delay(1000)
  )
}

interface Element {id: string, childId: string | null}

工作示例https://stackblitz.com/edit/e499mk

【讨论】:

  • 这是 expand 的非典型用法......通常你实际上不会在 expand 内部递归,因为 expand 会为你递归。
  • @bryan60 hm,你是对的,更新了我的答案,只在扩展内提出请求。很酷,您已经注意到了,我已经将它与外部递归一起使用了一段时间,并且它确实有效
【解决方案2】:

expand 是去这里的好方法。很难用提供的代码使其精确,但它看起来像这样:

private _myMethod(urls: string[]) {

  ...

  return forkJoin(observables).pipe(
    catchError(err => {
      console.log(err)
      return of(null)
    })
  )
}

public myMethod(urls: string[]) {
  return this._myMethod(urls).pipe(
    // expand will feed the value of outter observable to start, and then call this function recursively with the result of subsequent calls inside expand
    expand(json => {
      if (json.urls.length) {
        // expand calls itself recursively
        return this._myMethod(json.urls);
      }
      return EMPTY; // break
    }),
    // expand emits outter result and then results of recursion one by one. how you collect this is up to you
    // reduce is an option to collect all values in an array like this (like a forkJoin of your forkJoins)
    // reduce((acc, val) => acc.concat([val]), []) 
    // last is an option if you only want the last recursive call (or first if none from recursion)
    // last()
    // or omit these entirely if you want the results one by one.
  )
}

【讨论】:

    猜你喜欢
    • 2019-01-20
    • 2020-08-01
    • 1970-01-01
    • 2019-09-12
    • 2021-08-28
    • 1970-01-01
    • 2016-02-21
    • 2013-08-02
    • 2021-11-15
    相关资源
    最近更新 更多