首页 > 解决方案 > 是否有一个操作符可以用作 concatMap 但具有多个内部可观察对象

问题描述

我正在使用 observable 来查询我的数据库。这个 observable 将返回一个包含所有找到的匹配对象的数组。我的问题是我想用我将从另一个 API 检索到的更多细节来映射 observable。

我尝试了 concatMap 但它只让我将 1 个 observable 嵌套在初始 observable 中

const usersAPI$: Observable<Users[]> = //  something
const assistsAPI$: Observable<Assists[]> = //  something

const modifiedAssists$ = assistsAPI$.find().pipe(
  concatMap(assists =>
    assists.map(assist => usersAPI$.get(assist.userID)
       .pipe(
          map(user => 
            assist = {...assist}, ...{userName: user.userName}
          )
        )
    )
  )
);

您可以在 stackblitz 上看到一个类似的工作示例, https: //stackblitz.com/edit/rxjs-concatmap-issue-stackoverflow 其中“结果”是使用 concatMap 的正确方法,而“结果 2”是不工作的我期望的工作方式

标签: typescriptrxjs

解决方案


你必须以某种方式处理你内部的 Observable 数组。您可以使用forkJoin,mergeconcat根据您的需要。

分叉加入

forkJoin将并行处理您的内部 API 调用,并在所有 API 调用完成后返回一个数组。请注意,内部的 Observables 必须完成。我认为这应该适合您的应用程序。

import { forkJoin } from 'rxjs';

const modifiedAssists$ = assistsAPI$.find().pipe(
  concatMap(assists => forkJoin(assists.map(assist => someObservable ))
);

合并

merge将立即订阅所有内部 API 调用,并在所有调用到达时一一发出结果。

import { merge } from 'rxjs';

const modifiedAssists$ = assistsAPI$.find().pipe(
  concatMap(assists => merge(...assists.map(assist => someObservable )),
  // toArray() add the toArray operator if you need the result as an array
);

这将为您的 stackblitz 提供所需的结果,但我认为您的 stackblitz 有点误导,而不是您在问题的示例代码中寻找的内容,因为您的 stackblitz 中的内部 Observable 多次发出并且最终输出是不是一个数组。如果内部请求的顺序无关紧要,它们都会发出一个值然后完成,您需要将所有请求的结果作为一个数组,只需使用forkJoin.

连接

concat将一个接一个地订阅所有内部 API 调用。序列中的下一个 Observable 只有在前一个完成后才会被订阅。因此,执行将比 with 慢,forkJoin或者merge因为下一个 HTTP 请求将仅在前一个返回值之后执行。如果必须按照与数组userAPI中的顺序相同的顺序对您的特定调用进行调用,请使用此选项。assists

import { concat } from 'rxjs';

const modifiedAssists$ = assistsAPI$.find().pipe(
  concatMap(assists => concat(...assists.map(assist => someObservable )),
  // toArray() add the toArray operator if you need the result as an array
);

推荐阅读