【问题标题】:How can I get value of RxJs Observable in a nested array of objects to resolve?如何在要解析的嵌套对象数组中获取 RxJs Observable 的值?
【发布时间】:2021-11-12 01:53:08
【问题描述】:

我目前正在发出一个返回某些文件和用户数据的请求。

对于每个文件,我想返回一个包含数据的对象,但其中一个键依赖于另一个请求。

我怎样才能发出这个请求,以便getData 函数等到内部可观察对象解析为一个值?

function getData() {
    return forkJoin([
             filesApiRequest),
             userApiRquest
           ])
        .pipe(map(([files, userInfo]) => {
          return files.getFilesList()
              .map((file) => {
                const name = file.getName();
                const importantInfo = importantInfoCall(userInfo.name, name); // returns an observable. 
                // How can I get the value from this before returning? I need this piece of data for each 
                // file in the files list. 

                return {
                  data1,
                  data2,
                  name,
                  ...,
                  hasImportantInfo: importantInfo
                };
              })
        }));
  }

【问题讨论】:

  • 我将switchMap(而不是map)与forkJoinswitchMap的返回结果)结合使用。这里的想法是等待所有importantInfoCall 调用(我假设它们本质上是异步的)完成,然后对每次调用的结果执行您需要的操作。您可能希望将每个调用结果与它所属的相关文件配对以作为上下文。

标签: javascript angular rxjs angular2-observables


【解决方案1】:

您需要使用“高阶映射运算符”(switchMap),它将订阅您的内部可观察源并发出您需要的数据。在您的情况下,您需要进行多次调用(每个文件一个),因此您可以将文件列表映射到发出所需数据的可观察对象数组。您可以再次使用forkJoin 将所有这些调用包装到一个可观察对象中:

function getData() {
    return forkJoin([filesApiRequest, userApiRquest]).pipe(
        switchMap(([files, userInfo]) => forkJoin(
            // return array of observables
            files.getFilesList().map(f => toDataWithImportantInfo$(f, userInfo))
        ))
    );
}
function toDataWithImportantInfo$(file, userInfo) {
    const name = file.getname();

    return importantInfoCall(userInfo.name, name).pipe(
        map(importantInfo => ({
            data1,
            data2,
            name,
            ...,
            hasImportantInfo: importantInfo
        })
    );
}

forkJoin 在您有大量请求时不是最佳解决方案,因为它会同时执行所有请求(也许您不想一次启动 500 个 http 请求)。

为了限制请求的数量,我们可以使用merge来代替,因为它提供了一个并发参数:

function getData() {
    return forkJoin([filesApiRequest, userApiRquest]).pipe(
        switchMap(([files, userInfo]) => merge(
            files.getFilesList().map(f => toDataWithImportantInfo$(f, userInfo))
        , 5)), // MAX 5 CONCURRENT
        toArray()
    );
}

forkJoin 在所有源完成时发出一个包含所有结果的数组。 merge 单独发出每个结果,因此如果您想在所有内部源完成后发出单个数组(而不是单独发出),则需要toArray

【讨论】:

    猜你喜欢
    • 2022-01-15
    • 2022-01-01
    • 2020-02-08
    • 2020-05-18
    • 2021-09-01
    • 2018-10-12
    • 2021-11-29
    • 1970-01-01
    • 2021-11-30
    相关资源
    最近更新 更多