RxJS重构嵌套的映射语句

时间:2016-10-21 06:53:38

标签: angular refactoring rxjs code-cleanup rxjs5

我有一项使用@angular/http从API加载数据的服务。 我想使用此数据为我的Components创建检索数据的投影。

因此我写了以下代码:

getById(id: string) {
  return this.http
    .get(`https://my-api.io/${id}`)
    .map(response => response.json())
    .map(contracts =>
      contracts.map(contract =>        # <- Nested map
        new Contract(
          contract['id'],
          contract['description']
        )
      )
    );
}

第6行行中,我有一个嵌套的map - 语句,降低了我的代码的可读性。

问题

我可以做得更好吗?在RxJS中是否有一个操作符,我可以使用它而不是创建这种嵌套?

提前致谢!

3 个答案:

答案 0 :(得分:3)

我建议使用flatMap/selectMany将嵌套数组展平为每个单个数组元素的新流。在下一步中,您可以使用RxJS.map()进行实际映射。最后将带有RxJS.toArray()的所有映射数组元素收集到一个提供单个数组事件的新observable中:

const stream = $http('http://jsonplaceholder.typicode.com/posts')
 .map(res => res.data)
 .flatMap(posts => posts)
 .map(post => Object.assign({}, post, { status: false }))
 .toArray();

请在此处查看示例:http://jsbin.com/vigizihiwu/1/edit?js,console

但我也会考虑:真的有必要这样做吗?如果您只有一个订户,请将收到的数组映射到那里:

const stream = $http('http://jsonplaceholder.typicode.com/posts')
 .map(res => res.data);

stream.subscribe(res => {
  const posts = res.map(post => Object.assign({}, post, { status: false }));
  console.log(posts);
});

答案 1 :(得分:2)

感谢@Alexander T.。在我看来,他提出了一种绕过嵌套map的好方法 - 声明:http://jsbin.com/hududiq/1/edit?js,console

现在我的代码如下所示:

getByAccountId(id: string) {
  return this.http
    .get(`http://my-api.io/${id}`)
    .map(contractsData => contractsData.json())
    .concatAll()
    .map(contract => Observable.of(new Contract(
                                    contract['id'],
                                    contract['description'])))
    .combineAll();
}

答案 2 :(得分:2)

这似乎是一件非常简单的事情。

如果您想不惜一切代价避免嵌套map()(即使这是两种完全不同的方法),您只能在结果数组中使用一个map()然后forEach()

new Observable.of(testData)
  .map(contractsData => {
    var objects = [];
    JSON.parse(contractsData).forEach(o => objects.push(new Contract(o['id'], o['description'])));
    return objects;
  })
  .subscribe(val => console.log(val));

这将返回与您的代码相同的结果。

查看实时演示:http://plnkr.co/edit/NQgRVSCQGgPvTkPPGz7O(我还包含了您的代码以证明结果相同)。

我个人使用两个map(),因为它更简单:

new Observable.of(testData)
  .map(contractsData => JSON.parse(contractsData).map(o => new Contract(o['id'], o['description'])))
  .subscribe(val => console.log(val));

顺便说一下,所有以*all结尾的运算符都使用更高阶的Observables(也就是Observables发出其他Observables),我很惊讶你的代码可以工作,因为你将普通数组传递给.concatAll()而不是一个可观察者。由于its inner subscriber,它原来是.concatAll()的无证功能。 According to the documentation这不应该工作。