首页 > 解决方案 > 如何在第一个可观察输出用作第二个输入的时候进行 2 个可观察 / 2 个 http 调用?

问题描述

我陷入了使用toPromise()异步方法在我的 Angular 应用程序中获取 http 数据的情况。我必须使用要传递给第二个承诺的第一个承诺数据作为再次获取数据的输入。

但是执行并没有发生在我想要的流程中。

我的TS-

    IdSelection() : number[]{

    var Ids : any[]=[];
    this.selection.selected.forEach(element => {
      Ids.push(element.Id);
    });

    var commIds : number[]=[];
    Ids.forEach(async element => {
    const res =  await this.TaskService.getCmntDetails(element , 0 , '%27%27').toPromise();
    if(res["commentId"] !=null){
      res["commentId"].forEach(async data => {
        const innerRes = await this.TaskService.getCmntDetails(0, Number(data) , '%27%27').toPromise();
        innerRes["commentNewId"].forEach(ele => {
          commIds.push(ele);
        });
      });
    }
    
    });

    return commIds;
  }

当我调用这个方法时,我得到了resvariable 中的值,但不久之后执行将转到 return 语句,它返回 null 。

当我在它返回 null 后进行调试和检查时,执行返回到第二个 promise 并执行了事情。

任何人都可以帮我解决如何在第一个可观察输出用作第二个输入的时候进行 2 个 observables / 2 个 http 调用吗?

TIA

标签: angular

解决方案


您需要创建一个最终返回所需 ID 的可观察管道:

你的例子:

from(this.selection.selected).pipe(
  map(element => element.Id),
  mergeMap(element => this.TaskService.getCmntDetails(element, 0, '%27%27')),
  filter(res => res["commentId"] != null),
  mergeMap(res => from(res["commentId"])),
  mergeMap(data => this.TaskService.getCmntDetails(0, Number(data), '%27%27')),
  mergeMap(innerRes => from(innerRes["commentNewId"])),
  toArray()
);

让我一步一步解释这是做什么的:

这将创建一个选定元素(对象)的流。

from(this.selection.selected).pipe(

这将获取每个对象并将其映射到其Id字段。

  map(element => element.Id),

这将为每个上游元素启动异步调用。这些调用是异步启动的,并且可能以任何顺序解决。

  mergeMap(element => this.TaskService.getCmntDetails(element, 0, '%27%27')),

您只需要那些具有有效数据的结果,这会过滤结果。

  filter(res => res["commentId"] != null),

这会将commentId字段“扩展”为新的 id 流。

  mergeMap(res => from(res["commentId"])),

这再次启动并行调用以获取每个 id 的数据,同样,结果可能以任何顺序返回。

  mergeMap(data => this.TaskService.getCmntDetails(0, Number(data), '%27%27')),

接下来我们再次“扩展”该字段commentNewId并返回一个流。

  mergeMap(innerRes => from(innerRes["commentNewId"]))

最后我们收集所有结果并将它们制成一个数组

  toArray()

然后,您可以通过订阅或将其转换为 Promise 来使用上述流,有很多选择。

编辑

额外提示,如果您想要错误处理,您可以在整个流上执行,或者您可以捕获并忽略单个调用中的错误,例如:

  this.TaskService.getCmntDetails(element, 0, '%27%27').pipe(catchError(_ => EMPTY))

推荐阅读