避免在循环中使用嵌套的可观察订阅的正确方法是啥?

Posted

技术标签:

【中文标题】避免在循环中使用嵌套的可观察订阅的正确方法是啥?【英文标题】:What is the correct way to avoid using a nested observable subscription in a loop?避免在循环中使用嵌套的可观察订阅的正确方法是什么? 【发布时间】:2017-05-04 05:54:39 【问题描述】:

我通过 Angularfire2 使用 Angular2 和 Firebase 从 Firebase 实时数据库(基本上是一个大型 JSON 对象)获取一些数据。

我有一个投票系统。民意调查位于“民意调查”节点中,民意调查响应位于“民意调查”节点中。要将这些链接在一起,我使用了“投票响应链接”节点。

所以基本上,要获得投票响应,我必须获取所有链接,然后从链接中获取响应。

下面的代码有效,但我觉得这是一种糟糕的做法。这么一说,我也不知道怎么做才对。

this.teamPollsService.getPollLinkList(id).subscribe((linkList) => 
    this.responses = [];
    for (let link of linkList) 
        this.teamPollsService.getResponse(link['$key']).subscribe((response) => 
            this.responses.push(response);
        );
    
);

我希望有人能阐明执行此操作的正确方法及其背后的原因?

任何帮助将不胜感激。

谢谢。

【问题讨论】:

【参考方案1】:

如果您想以 RxJS 方式执行此操作,则可以使用 concatAll() 解压缩列表,然后使用 concatMap() 将每个项目转换为您想要的任何项目 this.teamPollsService

this.teamPollsService.getPollLinkList(id)
    .concatAll()
    .concatMap(link => this.teamPollsService.getResponse(link['$key']))
    .subscribe(team => console.log(team));

(我没有测试这段代码)

运算符concatAll() 展平数组(请参阅RxJS: JSON data with an array, processing each item further in the stream 或Merge subarrays using Observables)。然后concatMap() 从内部 Observable 重新发出一个值。

您也可以使用mergeMap(),它不会等到前一个 Observable 完成(不保证相同的项目顺序)。

【讨论】:

嗨,马丁。感谢您的回答。这部分对我有用。问题是即使存在 2 个或更多,它也只返回 1 个“响应”。 一个响应在哪里? 在最后的订阅console.log中。一项民意调查可以有多个响应,这意味着有多个链接 如果getPollLinkList() 发出多个数组,则没有区别。只需确保getPollLinkList() 在第一次发射后没有发送完整的信号。 所以也许我在这里感到困惑,但是当我调用 getPollLinkList().concatAll().concatMap(link => console.log(link)) return... 时,它只记录 1/4 个对象(第一个)。这是正确的吗?

以上是关于避免在循环中使用嵌套的可观察订阅的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何取消订阅路由解析类中的可观察对象

使用视图控制器淘汰嵌套的可观察对象

不需要的可观察服务订阅

嵌套可观察订阅问题,无法取消订阅

React 如何订阅在另一个组件中声明的可观察对象

如何在一个循环执行ajax方法里面嵌套的ajax方法