RxJS 重构嵌套 map 语句

RxJS Refactor nested map statement

我有一项服务使用 @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']
        )
      )
    );
}

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

问题

我可以做得更好吗? RxJS 中是否有一个运算符,我可以使用它来代替创建这种嵌套?

提前致谢!

感谢@Alexander T.. In my opinion he proposed a nice way to get around the nested map-Statement: 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();
}

用这种方法做一件非常简单的事情似乎非常复杂。

如果您想不惜一切代价避免嵌套 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));

这将 return 与您的代码产生相同的结果。

查看现场演示: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()一个 Observable 的。它原来是 .concatAll() 的一个未记录的功能,感谢 its inner subscriber. According to the documentation 这不应该工作。

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

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);
});