3

我收到一个 HTTP 响应,如果一切顺利,它包含一个数组,编码为 JSON。
我想得到这个数组,过滤掉一些项目,并将传递的项目作为事件处理。

到目前为止我所做的是:

    return this._http.get(url)
        .map((res:Response) => res.json())
        .map((data:any) => {
            if (!Array.isArray(data) || data.length == 0) {
                throw new Error("No items returned, URL: " + url);
            }
            let projects = <ProjectModel[]>service.fromJSONarray(data, this._http);
            return Observable.from(projects)
                .filter((project: ProjectModel) => project.parentProject == null)
                .subscribe(project -> ...)
        })

但是我不喜欢嵌套。我认为有一种方法可以做到这一点:

    return this._http.get(url)
        .map((res:Response) => res.json())
        .map((data:any) => {
            ...
            let projects = <ProjectModel[]>service.fromJSONarray(data, this._http);
            ???
        })
        .filter((project: ProjectModel) => project.parentProject == null)
        .subscribe(project -> ...)

如何做到这一点?

4

2 回答 2

7

假设您使用的是 RxJS 5,即使使用高阶 Observables 也可以使用更简单的方法concatAll()及其未记录的功能来展平嵌套数组concatAll()

let data = '[{"id":1},{"id":2},{"id":3},{"id":4}]';

Observable.of(data)
    .map(JSON.parse)
    .concatAll() // each object is emitted separately
    .map(p => p) // transform to ProjectModel
    .filter(p => true) // filter whatever you want
    .subscribe(v => console.log(v));

如果service.fromJSONarray只返回一个实例,ProjectModel就可以这么简单。如果你需要service.fromJSONarray返回一个数组,你可以把它放在map(JSON.parse)and之间concatAll()。此演示打印到控制台:

{ id: 1 }
{ id: 2 }
{ id: 3 }
{ id: 4 }

但是,如果您要返回一个 Observable ,service.fromJSONarray它会发出其他 observable ,因为它需要执行一些您需要使用的额外 HTTP 请求,concatMap()或者flatMap()取决于您是否要保持相同的项目顺序:

let data = '[{"id":1},{"id":2},{"id":3},{"id":4}]';

function fromJSONarray(arr) {
    return Observable.from(arr)
        .flatMap(p => Observable.of(p));
}

Observable.of(data)
    .map(d => fromJSONarray(JSON.parse(d)))
    .concatAll()
    .map(p => p) // transform to ProjectModel
    .subscribe(v => console.log(v));

结果是一样的。

类似的问题:

于 2016-12-12T08:18:44.400 回答
1

每当您映射到 Observables 数组时,您都应该考虑flatMap

在您的示例中,这看起来像:

return this._http.get(url)
    .map((res:Response) => res.json())
    .flatMap((data:any) => {
        if (!Array.isArray(data) || data.length == 0) {
            throw new Error("No items returned, URL: " + url);
        }
        let projects = <ProjectModel[]>service.fromJSONarray(data, this._http);
        return Observable.from(projects);
    })
    .filter((project: ProjectModel) => project.parentProject == null)
    //...etc

或者,更简单地说

Observable
  .range(0, 2)
  .flatMap(() => Observable.from([1, 2, 3]))
  .filter((foo) => foo !== 1)
  .subscribe((res) => console.log(res));

// 2
// 2
// 3
// 3
于 2016-12-12T00:10:03.367 回答