【问题标题】:Run nested http-requests with forkJoin使用 forkJoin 运行嵌套的 http 请求
【发布时间】:2019-09-26 03:09:16
【问题描述】:

我有如下数据:

[
  {
    id: 1,
    pets: [
      {
        id: 11,
        pet: 'Zebra'
      },
      {
        id: 12,
        pet: 'Giraffe'
      }
    ]
  }
]

我从获取请求中获得。对于数组和pets数组中的每个项目,我需要根据id从另一个端点获取每个petmood,例如返回:

{
  id: 11,
  mood: 'hungry'
}

所以请求后的最终结果是这样的:

[
  {
    "id": 1,
    "pets": [
      {
        "id": 11,
        "pet": "Zebra",
        "mood": "hungry"
     },
     {
       "id": 12,
       "pet": "Giraffe",
       "mood": "happy"
     }
   ]
  }
]

我已尝试对所有pets 使用forkJoin,但无法使其正常工作。 Stackblitz 下面是一种尝试:

getCombined() {
  return of(this.parent).pipe(
    switchMap(families => {
      return families.map(family => {
        return forkJoin(
          family.pets.map(pet => {
            return this.getMood(pet.id).pipe(
              map(data => {
                pet.mood = data.mood;
                return family;
              })
            )
          })
        )
      })
    }), switchMap((d) => d)
  );
}

它正确地返回了 3 个外部对象,但它们看起来都是同一个对象。如何得到正确的结果?在此先感谢,这里是 Stackblitz:https://stackblitz.com/edit/angular-ttpcvu?file=src%2Fapp%2Fapp.component.ts

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    像这样试试:

      getCombined() {
        return forkJoin( // don't need the of and whatnot.
          this.parent.map(family => {
            return forkJoin(
              family.pets.map(pet => {
                return this.getMood(pet.id).pipe(
                  map(mood => {
                    pet.mood = mood.mood; //assign mood
                    return pet; // return populated pet.
                  })
                );
              })
            ).pipe(
              map(pets => {
                family.pets = pets; // assign the pets here
                return family; // return populated family.
              })
            )
          })
        );
      }
    

    闪电战:https://stackblitz.com/edit/angular-uwqclm?file=src/app/app.component.ts

    您需要为外部集和内部集创建一个 forkjoin 才能正确执行,并且您需要在正确的位置完成分配。

    【讨论】:

    • 完美运行!谢谢。对更“复杂”的 rxjs 事情仍然很陌生,但我会到达那里;)非常感谢您的帮助!
    【解决方案2】:

    在下面的代码中,我们将对象数组作为可观察流进行流式传输,然后 再次流式传输宠物并创建假 Obserbale(api 调用)并将响应映射到宠物属性,然后再次将所有宠物与各自的所有者一起制作。

    const { fromEvent, merge, of, from } = rxjs;
    const { map, filter, concatMap, toArray, tap, delay, concatAll, mergeMap,mergeAll } = rxjs.operators;
    // Write TypeScript code!
    const appDiv = document.getElementById('app');
    appDiv.innerHTML = `<h1>if you dont want Asynchronous request then you can use concat instead of merge</h1>`;
    console.clear();
    
    const data$ = of([{
      id: 1, pets: [
        { id: 11, pet: 'Zebra' },
        { id: 12, pet: 'Giraffe' }
      ]
    },
    {
      id: 2, pets: [
        { id: 21, pet: 'Zebra' },
        { id: 22, pet: 'Giraffe' }
      ]
    }
    ])
    const q = (x) => {
      // Fake http call 
      // you can make your api call here 
      const oneSecondSource$ = of(x['id']).pipe(delay(1 * x.id))
      return oneSecondSource$.pipe(map(abs => {
        const res = Math.floor(Math.random() * Math.floor(1)) === 0 ? 'hungry' : 'happy';
        // and map the resulatant mood
        return { ...x, mood: res }
      }));
    }
    
    const p = (obj) => {
      // mapping each
      return from(obj.pets).pipe(mergeMap(q), toArray(), map(a => {
        return { id: obj.id, pets: a }
      }))
    }
    const example$ = data$.pipe(mergeMap(a => from(a).pipe(map(p))),
      mergeAll(),
      toArray()
    );
    example$.subscribe(console.log)
    <script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
    
    <div id="app"></div>

    这里是stackblitz solution you can refer

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 2019-02-28
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      相关资源
      最近更新 更多