【问题标题】:Creating recursive Observable loop?创建递归可观察循环?
【发布时间】:2018-06-06 06:59:02
【问题描述】:

我很难弄清楚如何使用 Observables 为 api 调用创建递归循环。

场景: 我调用外部 API,它返回如下内容:

{
 data: {something, something, something},
 next: "url for next set of data"
}

只要响应在next 中有值,我就需要继续调用相同的函数将所有数据收集到一个对象中。

我设法在另一个使用 Promises 的项目上做到了这一点,在该项目中,我使用 concat() 函数将返回的数据映射到单个数组中,但不知何故我无法理解我应该如何使用 Observables 做到这一点。

使用 Promise 的工作示例:

getData: function(url, params, headers){
    return new Promise((resolve, reject) => {
        axios.get(url, {
            params: params,
            headers: headers,
        }).then((response) => {
            let responseData = response.data.data[0];
            if (response.data.next) {
                this.getData(response.data.next, {}).then((resp) => {
                    for (let dataSet of responseData.dataSets) {
                        let row = resp.dataSets.find(i => i.variable === dataSet.variable)
                        if (row) {
                            dataSet.data = dataSet.data.concat(row.data)
                        }
                    }
                    resolve(responseData);
                }).catch((error) => {
                    reject(error)
                })

            } else {
                resolve(responseData);
            }
        }).catch(error => {
            reject(error)
        })
    })
}

【问题讨论】:

  • 您可以在此处发布您使用 promise 所做的代码。
  • 编辑问题以包含示例

标签: rxjs angular2-observables


【解决方案1】:

您可以使用.expand() 运算符。此递归的终止条件是next 属性为falsy。使用三元运算符,代码只是一个衬里:

expand(({data, next}) => next ? getData(next): Observable.empty() )
    .subscribe(result => console.log(result));

这是工作的JSBin。我嘲笑了很多东西,但它应该是微不足道的。

【讨论】:

  • 非常有帮助,我可以接听电话,而且很容易阅读。唯一我不太明白的部分是如何绘制数据,concatMap 本身并不能解决问题,因为我只想在数据集中连接数据......对不起,我今天过得很慢......跨度>
【解决方案2】:

结束对我有用的解决方案:

let obs = this.getData(endpoint, options).pipe(
  expand(({ next }) => {
    // This could be oneliner but I had to alter options for the calls after the first one for my own case
    return next ? this.getData(next, options) : Observable.empty()
  }),
  concatMap(({data}) => data)
)

obs.subscribe(
  data => mapthedata(data),
  error => error,
  complete => {
    // do something with the mapped data
  }
)
function mapthedata(data) {
  // here you should combine the data results into one, f.ex pushing to local variable
}

【讨论】:

    【解决方案3】:

    今天刚遇到这个类似的问题,这是我的尝试。我认为困难的部分是正确思考您要实现的目标,然后找到正确的运营商来支持它。

    在这种情况下,从第一个 observable 开始,我们想要 expand 并继续递归地发出值直到完成。最后我们要收集的是这个 observable 发出的所有值,那时我用谷歌搜索了正确的关键字并找到 toArray 来支持这种情况。

    参考:How to collect array of emitted values from Observable.from?

    this.getData(endpoint, options).pipe(
      expand(({ next }) => {
        return next ? this.getData(next, options) : Observable.empty()
      }),
      toArray(), // wait for the observable to complete and collect all emitted values
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 2019-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      相关资源
      最近更新 更多